Wednesday, December 14, 2011

NB CLI Application with Maven

Sometimes you want to harness the power of the NetBeans platform without being worried about a user interface.
Lets’ see how to do it with Maven

Select the Create Module Project item


In the application module (the orange module icon)
Change the dependencies to


        
            ${project.groupId}
            NbCli-branding
            ${project.version}
                
        
            ${project.groupId}
            NbCli-sample
            ${project.version}
        
        
            org.netbeans.modules
            org-netbeans-bootstrap
            ${netbeans.version}
            nbm
        
        
            org.netbeans.api
            org-openide-filesystems
            ${netbeans.version}
            nbm
        
        
            org.netbeans.api
            org-openide-util-lookup
            ${netbeans.version}
            nbm
        
        
            org.netbeans.modules
            org-netbeans-core-startup
            ${netbeans.version}
            nbm
        
        
            org.netbeans.api
            org-openide-modules
            RELEASE701
            nbm
        
     

Change the dependencies section of your NbCli-Sample to the following


        
            org.netbeans.api
            org-netbeans-api-annotations-common
            ${netbeans.version}
        
        
            org.netbeans.api
            org-netbeans-modules-sendopts
            ${netbeans.version}
            nbm
        
        
            org.netbeans.api
            org-openide-modules
            ${netbeans.version}
        
        
            org.netbeans.api
            org-openide-util
            ${netbeans.version}
        
        
            org-openide-util-lookup
            org.netbeans.api
            ${netbeans.version}
        
    

Although it seems like we’re adding more dependencies we’re actually putting the platform on a diet and getting rid of all the User Interface related stuff that we don’t need.

In order to give your command line application a static main you need to use an Installer / Activator




The restored() becomes your public static void main

package com.mycompany.nbcli;

import org.openide.LifecycleManager;
import org.openide.modules.ModuleInstall;
import org.openide.util.Exceptions;

public class Installer extends ModuleInstall {

    @Override
    public void restored() {
        try {
            System.out.println("My NetBeans CLI application has started");
            Thread.sleep(5000);
            System.out.println("Ok we've done all our super duper hard work. Lets exit");
            LifecycleManager.getDefault().exit();
        } catch (InterruptedException ex) {
            Exceptions.printStackTrace(ex);
        }
    }
}

However there is still one problem...


Splashscreens aren't very CLI, so lets remove it.

Go to your application module and add the following snippet to the POM

        
            
                org.codehaus.mojo
                nbm-maven-plugin
                
                    --nosplash
                
            
        
    

Monday, October 3, 2011

NetBeans: increasing your code awareness

Take a look at this snippet:

Now I'm sure that we're all familiar with the grey underline that tells us that a variable is not being used.
But look at the value "Robert" - NetBeans now tells you when you're not using a value that is assigned to an otherwise used variable.

Just a tidbit of what you can look forward to in the upcoming release of NetBeans :)

EDIT Try out all the new functionality in NetBeans 7.1 Beta

Sunday, July 17, 2011

Encrypting Passwords is easy

Well atleast it is when you use JASYPT (Java Simplified Encryption)

Lets use the BasicPasswordEncryptor for our first attempt

    BasicPasswordEncryptor basicEncryptor = new BasicPasswordEncryptor();
    System.out.println(basicEncryptor.encryptPassword("My Very Strong Password"));

The thing that I find interesting here is every time I run this simple program i get a different encrypted password


HqFktdLI4FRmm1FZRpl1aPwaZwMZHHKx
C1G24DHVoApEBMo2OGboQCU92bM4Vz3/
PN1Bfp2C1SKp+jWMIbfwv4FryTvbi48b
sr54VjzHllbIOZkCMT8+5gpEJYvOMZZ/
leS3xZ9eavcmLdpry16TWShD84YqDZBf

That can't be right, can it? Lets check

   System.out.println(basicEncryptor.checkPassword("My Very Strong Password", "HqFktdLI4FRmm1FZRpl1aPwaZwMZHHKx"));
   System.out.println(basicEncryptor.checkPassword("My Very Strong Password", "C1G24DHVoApEBMo2OGboQCU92bM4Vz3/"));
   System.out.println(basicEncryptor.checkPassword("My Very Strong Password", "sr54VjzHllbIOZkCMT8+5gpEJYvOMZZ/"));
   System.out.println(basicEncryptor.checkPassword("My Very Strong Password", "PN1Bfp2C1SKp+jWMIbfwv4FryTvbi48b"));
   System.out.println(basicEncryptor.checkPassword("My Very Strong Password", "leS3xZ9eavcmLdpry16TWShD84YqDZBf"));

This outputs:

true
true
true
true
true



errrr huh? Whats going on here? The answer is salting. For a fuller explanation read the JASYPT explanation

The BasicEncryptor uses MD5 as its encryption algorithm, if you decide that this isn't good enough for your needs you can always use the StrongPasswordEncryptor  that uses SHA-256 for its encryption.

   StrongPasswordEncryptor strongEncryptor = new StrongPasswordEncryptor();
   System.out.println(strongEncryptor.encryptPassword("My Very Strong Password"));

Which outputs pFzPnk1H8aitAjf4BdMRmKKQ1v6TzXUBCXAlsz+VXN/GK/bhd68IYO4f6+Wu2aRh

So whats your excuse for not doing it?

Sunday, June 26, 2011

Getting Started with Maven Enterprise Applications

There seems to be a little bit of a funny in the Enterpise application that NetBeans generates which can completely befuddle you if you aren't aware of it:

SEVERE: Expected to find an expanded directory for submodule MyEnterpriseApp-web-1.0-SNAPSHOT.war but found a JAR. If this is a directory deployment be sure to expand all submodules.

Seen that error before? Well stick with me and I'll show you how to get rid of it.

Lets create a new project
Projects -> Maven -> Enterprise Application



Create a Session Bean in your EJB project to make the JAR file valid.

package com.acme;

import javax.ejb.Stateless;
import javax.ejb.LocalBean;

/**
*
* @author Tim
*/
@Stateless
@LocalBean
public class SimpleSessionBean {

public String hello(String name) {
return "Hello " + name;
}

}


So far this is all pretty standard stuff, and if you try and run your application now you'll be met with the above mentioned error. However resolving the said error is actually quite simple.

Open the EAR project and edit the POM.xml - the build section before you edit it should look like this.

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<version>2.4.2</version>
<configuration>
<version>6</version>
<defaultLibBundleDir>lib</defaultLibBundleDir>
</configuration>
</plugin>
</plugins>
<finalName>MyEnterpriseApp-ear</finalName>
</build>


After you edit it, it should look as follows.

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<version>2.4.2</version>
<configuration>
<version>6</version>
<defaultLibBundleDir>lib</defaultLibBundleDir>
<modules>
<webModule>
<groupId>com.acme</groupId>
<artifactId>MyEnterpriseApp-web</artifactId>
<unpack>true</unpack>
<!--<contextRoot></contextRoot>-->
</webModule>
<ejbModule>
<groupId>com.acme</groupId>
<artifactId>MyEnterpriseApp-ejb</artifactId>
<unpack>true</unpack>
</ejbModule>
</modules>
</configuration>
</plugin>
</plugins>
<finalName>MyEnterpriseApp-ear</finalName>
</build>


Whats happened here is that GlassFish is expecting the application to be in the exploded format, but it isn't.
By added the <webModule> and <ejbModule> and specifically the <unpack>true</unpack> line we are telling the plugin to explode the modules.

Hope this stops somebody else from wasting a good part of their evening.

Thursday, March 10, 2011

Mercurial on IIS with basic Active Directories

Notes on how to install Mercurial on Windows Server 2008  with basic Active Directory authentication.

Credit to Jeremy Skinner and Ben Alabaster who wrote the original articles on this.
This is an updated combination of the 2 posts, using the latest compatible versions of Python and Mercurial, and one or 2 steps that wheren't included in either post.


  1. Download and install Mercurial (mercurial-1.8.0)
    1. Seems to require 32 bit even on 64 bit systems
    2. Select defaults
  2. Download and install Python (python-2.6.6)
    1. Seems to require 32 bit even on 64 bit systems
    2. Select defaults
    3. Add C:\Python26\ to system PATH
  3. Download and install MinGW (mingw-get-inst-20110211)
    1. Use pre-package repsoitory catalogues
    2. Install to C:\minGW
    3. Don't create start folder
    4. Select C++ compiler 
    5. Add C:\MinGW\bin to the system PATH
  4. Download Mercurial Python Library (http://mercurial.selenic.com/release/mercurial-1.8.tar.gz)
    1. Extract folder
    2. jump into the command line where you extracted the library to
    3. execute "python setup.py install build --compiler=mingw32"
  5. Install and setup IIS
    1. Server Manager > Roles > Add Roles > Install IIS
    2. Server Manager > Role Services > CGI (enable)
    3. Create hg directory
      1. mkdir c:\inetpub\wwwroot\hg
    4. IIS Manager > Sites > Default web Site > Refresh
    5. IIS Manager > Sites > Default web Site > Bindings > http port 40
    6. IIS Manager > Sites > Default web Site > hg > Handler Mappings > Add Script Map
      1. Request Path: *.cgi
      2. Executable: C:\Python26\python.exe
      3. Name: Python
      4. Yes on dialog box that appears
    7. IIS Manager > Sites > Default web Site  > START
  6. Setup the Mercurial Web
    1. mkdir c:\temp\hgClone
    2. cd c:\temp\hgClone
    3. hg clone http://selenic.com/report/hg
    4. copy hg\hgweb.cgi c:\inetpub\wwwroot\hg
    5. cd c:\
    6. rmdir /S /Q c:\temp\hgClone
    7. c:\>"c:\Program Files\Windows NT\Accessories\wordpad.exe" c:\inetpub\wwwroot\hg\hgweb.cgi
      1. Change the line "application = hgweb(config)" to "application = hgweb('c:\inetpub\wwwroot\hg\hgweb.config')"
    8. extract C:\Program Files\Mercurial\library.zip into c:\inetpub\wwwroot\hg\library\
    9. copy C:\Program Files\Mercurial\templates\ to c:\inetpub\wwwroot\hg\
  7. Initialize Repositories
    1. mkdir c:\repositories
    2. mkdir test 
    3. hg init test
  8. Configure
    1. add to C:\inetpub\wwwroot\hg\hgweb.config:
      1. [collections]
        C:\repositories = C:\repositories
  9. URL Rewriting
      1. download http://www.iis.net/expand/URLRewrite
    1. install
    2. IIS Manager > Sites > Default web Site > URL Rewrite > new Rule > blank Rule
      1. name: Rewrite to hgweb
      2. Match URL
        1. Requested URL: Matches the Pattern
        2. Using Wildcards
        3. Pattern: *
        4. ignore case: yes
      3. Conditions
        1. Logical Grouping: Match All
        2. Add Condtion
          1. Condition input: {REQUEST_FILENAME}
          2. Check if input string: Is Not a File
      4. Action
        1. Action Type: Rewrite
        2. Action Properties
          1. Rewrite URL: /hg/hgweb.cgi/{R:1}
          2. Append Query String: Yes
          3. Log rewritten URL: No
        1. Stop processing of subsequent Rules: No
  10. Authorisation Settings
    1. IIS Manager > Sites > Default web Site > Authentication
      1. Disable Everything
      2. Enable Basic
      3. Edit Basic
        1. default domain: yourdomain.com
    2. Edit c:\inetpub\wwwroot\hg\hgweb.config
      1. add line
        1. push_ssl = false
      2. add line 
        1. allow_push = <comma seperated list of developer domain names>

Monday, January 17, 2011

You're unique, Just like everyone else

So how do go about making your application unique, just like every other application that your company makes?

I reckon the NetBeans Platform in combination with Pinkmatter NetBeans Ribbon Library works a treat.

You work for a company called 'Motoring Madness', who have strived over the years to create a reputation as reliable vehicle retailers (an understandably difficult and unenviable task). They have recently been appointed sole resellers for Alfa Romeo and Lotus in the greater Tweebuffelsmeteenskootmorsdoodgeskietfontein metropolitan area.

Separate applications need to be created to meet the unique demands of these vehicle manufacturers whilst still retaining the corporate identity that Motoring Madness have worked so diligently to create.

Firstly I'm going to download the Pinkmatter NetBeans Ribbon Library, it comes with a very convenient test application that I'm going to corrupt (Sorry Chris…).

Here's how it looks in stock standard form.



Specifically, this is the area that we are interested in.



Now as cool as the NetBeans Logo is, it just doesn't fit with our Motoring Madness corporate Identity. So let’s dig into the source of the Ribbon Library and see if
we can change that.

Open the Flamingo Integration module and navigate to com.pinkmatter.modules.flamingo. In there you will see an image called app-button-icon24.png I wonder what happens if we swap that image out with our much vaunted Motoring Madness Logo

Note: If you’re still seeing the NetBeans logo, do a search in the test-ribbon project for app-button.png and delete it.


Now the brand manager is happy, his logo will be at the forefront of all the Motoring Madness applications

Everybody is yawning at the sheer excitement of applications all looking exactly the same, until some smart-aleck decides to try and brand his application.


And in the task-bar we get this


Which is decidedly cool.

Smart Aleck #2 decides that he wants to brand his applications, using the Alfa app as a reference.
Whilst switching between the Lotus and Alfa applications he discovers another cool trick.


The Lotus and Alfa Apps have different Icons whilst switching, ensuring that nobody will ever mistakenly receive a Lotus when they actually want an Alfa Romeo.


Now if I could only figure out a simple way to brand the netbeans.exe launcher my manager would leave me alone and I could figure out how to get past the easy levels on Sudoku.

Thursday, October 28, 2010

Basic Authentication and Authorization

When building commercial applications the twin issues of authentication and authorization are almost certain to arise at some point, the topic becomes even livelier when you throw a legacy infrastructure into the mix and want everything to work seamlessly.

So what’s a really nice and simple way of doing this? Let’s look at Apache Shiro and see how it simplifies things for us.

What is Apache Shiro? I think they say it best themselves
Apache Shiro is a powerful and easy-to-use Java security framework that performs authentication, authorization, cryptography, and session management. With Shiro’s easy-to-understand API, you can quickly and easily secure any application

Right - so let’s get our hands dirty, and see how we can leverage Shiro.


Create a Web application


New Project -> Maven -> Maven Web Application


Create a new Stateless Session Bean


HelloResource class

@Stateless
@Path("/message")
public class HelloResource {
    
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String sayHello() {
        return "hello someone";
    }

} 

Note that under your PersonalHello web project Netbeans has created a RESTful web services node, under which your HelloResource lives.

Right click the RESTful Web Services node and Select REST Resources configuration.


Change the name of the REST Resources Path, this will make NetBeans generate the web.xml file with your servlet adaptor.

Run your web app and you should see the Standard ‘Hello World!’ index page.

Go to http://localhost:8080/PersonalHello/rest/message and you should see your ‘hello someone’ message.


So now we know that our simple web service with no authentication is working, lets add Shiro into the mix and see how complicated things become!


Adding Shiro 

Add  the following dependencies to your projects pom.xml

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>1.0.0-incubating</version>
        </dependency>
        
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.6.1</version>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>1.6.1</version>
            <scope>runtime</scope>
        </dependency>

Note: Shiro has just graduated from the Apache Incubator, so expect a non-incubating release sometime soon.


Go to your web.xml and add the following



     <filter>
        <filter-name>ShiroFilter</filter-name>
        <filter-class>org.apache.shiro.web.servlet.IniShiroFilter</filter-class>
        <init-param>
            <param-name>config</param-name>
            <param-value>

                # The IniShiroFilter configuration is very powerful and flexible, while still remaining succinct.
                # Please read the org.apache.shiro.web.servlet.IniShiroFilter JavaDoc for information.

                # Quick Tip: Instead of having this configuration here in web.xml, you can instead
                # move all of this to a 'shiro.ini' file at the root of the classpath and remove
                # the 'config' init-param. Or you can specify the 'configPath' init-param and specify the
                # path to a resource at any location (url, file or classpath). This may be desired if the
                # config gets long and you want to keep web.xml clean.

                [users]
                # format: username = password, role1, role2, ..., roleN
                root = secret,admin
                guest = guest,guest
                presidentskroob = 12345,president,admin
                darkhelmet = ludicrousspeed,darklord,schwartz
                lonestarr = vespa,goodguy,schwartz

                [roles]
                # format; roleName = permission1, permission2, ..., permissionN
                admin = *
                schwartz = lightsaber:*
                goodguy = winnebago:drive:eagle5

                [urls]
                /rest/** = authcBasic

            </param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>ShiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>


Go New File -> Other -> properties



And add the following text to the file

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
#
# This file is used to format all logging output
log4j.rootLogger=TRACE, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %-5p [%c]: %m%n

# =============================================================================
# 3rd Party Libraries
# OFF, FATAL, ERROR, WARN, INFO, DEBUG, ALL
# =============================================================================
# ehcache caching manager:
log4j.logger.net.sf.ehcache=WARN

# Most all Apache libs:
log4j.logger.org.apache=WARN

# Quartz Enterprise Scheular (java 'cron' utility)
log4j.logger.org.quartz=WARN

# =============================================================================
# Apache Shiro
# =============================================================================
# Shiro security framework
log4j.logger.org.apache.shiro=TRACE
#log4j.logger.org.apache.shiro.realm.text.PropertiesRealm=INFO
#log4j.logger.org.apache.shiro.cache.ehcache.EhCache=INFO
#log4j.logger.org.apache.shiro.io=INFO
#log4j.logger.org.apache.shiro.web.servlet=INFO
log4j.logger.org.apache.shiro.util.ThreadContext=INFO








And finally let’s make our hello a little more personal. Change the sayHello method to the following


    public String sayHello() {

        StringBuilder builder = new StringBuilder();
        builder.append("Hello ");
        builder.append(SecurityUtils.getSubject().getPrincipal().toString());

        return builder.toString();
    }


Run your web-app again and go to http://localhost:8080/PersonalHello/rest/message you will now see a login prompt. Use ‘lonestarr’ as the user and ‘vespa’ as the password (or any of the other combinations that are in the config that you placed in the web.xml)
You will now be greeted by a personalised Hello, pretty nifty me think!

What have we done to achieve this?
1.    Added the dependencies to our project
2.    Made sure that log4j was configured
3.    Modified our web.xml with the Shiro specific config

  •     The important things to note here are:
         1. The Filter that in our case says every request must go through Shiro
         2. /rest/** = authcBasic  - This says that the urls here require basic authentication
         3. The users section

So not much work to achieve the authentication at all then.


Adding Authorization


Create a new class in your Web App:

import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
import org.apache.shiro.SecurityUtils;


public class AuthorizationInterceptor {

    @AroundInvoke
    public Object authenticate(InvocationContext context) throws Exception{

        if (!SecurityUtils.getSubject().hasRole("admin")){
            StringBuilder exBuilder = new StringBuilder();
            exBuilder.append("User: \'");
            exBuilder.append(SecurityUtils.getSubject().getPrincipal().toString());
            exBuilder.append("\' is not authorized to use this resource");


            throw new SecurityException(exBuilder.toString());
        }

        return context.proceed();
    }
}

And add the @Interceptors({AuthorizationInterceptor.class})  Annotation to your HelloResource class

package sparg.tim.personalhello;

import javax.ejb.Stateless;
import javax.interceptor.Interceptors;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.apache.shiro.SecurityUtils;

/**
 *
 * @author tsparg
 */
@Interceptors({AuthorizationInterceptor.class})
@Stateless
@Path("/message")
public class HelloResource {
    
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String sayHello() {

        StringBuilder builder = new StringBuilder();
        builder.append("Hello ");
        builder.append(SecurityUtils.getSubject().getPrincipal().toString());


        return builder.toString();
    }

}

Run your application and go to http://localhost:8080/PersonalHello/rest/message and login with ‘guest’ username ‘guest’ password (or any user that is not a part of the admin group).

You should now see an error page telling you that you are not authenticated to view this page.

If you log in with any of the other user codes that are members of the admin role (look in your web.xml to see which) you will proceed to the normal screen.


A couple of things to note:
  • Shiro has some very nifty hooks into both Authentication and Authorization so that you can leverage any existing infrastructure that you may have.
  • With the Way I have done the Authorization the App Server returns a HTTP 500(Internal Error), it would be nice if I could figure out how to return a HTTP 401 (Unauthorized)
  • You should most probably make the AuthorizationInterceptor a Default Interceptor, meaning you wouldn't have to annotate your classes for authorization.


I quite like this approach, as the authorization and authentication can be quite clearly moved away from any domain specific code.