Friday, June 22, 2012

Weblogic Custom Authentication Provider and Web Application Security Roles


In this post we will implement a Custom Authentication Provider that connects to a data base, checks the user credentials and retrieves the associated groups.

The Custom Authentication Provider passes the authenticated Subject for the Weblogic Security Framework so the Authorizations can be granted for the requested resource - the web application pages.

This example was based on the oracle documentation at
Oracle Fusion Middleware Developing Security Providers for Oracle WebLogic Server  and the code examples available at Database User Security Provider Sample.

I extended the provided code to validade the user credentials and return the groups stored in a data base. This way the security framework can decide if the subject contains the authorized principal to access the resource.



Required software: Weblogic Server 10.3.x, a database (Oracle XE is used here), eclipse (or other IDE, though it might require some coding and converting the project).

1. We need to first define a simple data base model to store our application users and groups.

I use 2 tables: TEST_USER - for users and USER_GROUP - to store user's groups.


I inserted the following data in the TEST_USER table:



And the following for USER_GROUP:




2. Go to WLS Admin Console and create a DataSource pointing to your data base. This data source will be used by our Authentication Provider to retrieve the user credentials and groups.


3. Download the basic Eclipse project from here and import into ecplise. You might need to resolve some dependencies. Basically you will need to add to you build classpath weblogic.jar, <BEA_HOME>/wlserver_10.3/server/lib and <BEA_HOME>/modules.

After the correct import, your project should look like the image below. Don't mind the CustomDBAuthenticationProviderMBean errors, we will get rid of them in the next steps.



4. There are 3 classes and a MBean xml definition file in the project. Let's take a look at each of them.

   a. DBAuthenticationProviderImpl.java - This is the custom authenticator, extending AuthenticationProviderV2. We will not modify much its methods, since we have a specific helper class to handle the DB connection and validation.
 
   b. DBLoginModuleImpl.java - The login module is the class that performs the actual job for authentication, but, as mentioned before, we will implement a helper class which will handle the specifics of database connectivity and credential checkings. The LoginModule will only call our helper and pass along its results to the security framework.
 
   c. DatabaseAuthenticator.java - This is where our code is implemented. In this class we lookup the datasource, execute queries to get user details and validate the credentials. The decision if the user exists, if it provided correct credentials and their assigned groups, are executed and passed to the LoginModule.
 
   d. DBAuthenticationProviderMBean.xml - This is the XML file where we define our MBean to manage our implementation properties in WLS admin console. There is a coupling between the classes mentioned before and the XML, since it will generate the bean that is referenced in the classes. There is also a dependency between the values provided to this XML and the ant task I provided to build, deploy and update the eclipse project. So, if you plan to change any names or values in this project, check the class comments to see what impact it will have.
 
5. To build the example, first check the build.xml and set the required properties to the equivalent in your environment. The buildAndDeploy task will compile, generate the MBean, package everything into a jar and deploy to your WLS mbeantypes folder, where it will be picked up by WLS at startup. At this point you can run the updateSources task and refresh your workspace. This will get rid of the errors regarding the MBean dependencies. It also makes it easier if you want to change de default implementation for our MBean, by adding different properties, for example. If you do so, you will have to run buildAndDeploy again to refresh the build.

If everything was correctly configured and the task completed successfully, you can go ahead and start up WLS.

6. Go to WLS AdminConsole > Security Realms > myrealm > Providers and click New. Choose the provider you named in your MBean XML definition, in my case, CustomDBAuthenticationProvider and give it a name.



7. Click in the provider you just created and make sure the control flag is set to OPTIONAL. In Provider Specific tab, fill the information required for the DS Lookup. The Principal Name and Principal Password are not required, unless you protected the DS from anonymous lookup (a good practice).



8. Go to WLS AdminConsole > Security Realms > myrealm > Providers and click in the DefaultAuthenticator. Change the Control Flag to SUFFICIENT.

9. Deploy a sample application prepared for this test case provided here or the eclipse project here. Note that the application defines 3 roles for 3 different protected resources in web.xml and weblogic.xml.

   a. <url-pattern>/super/*</url-pattern> are only authorized for users from SUPER_ADMIN group
   b. <url-pattern>/admin/*</url-pattern> are only authorized for users from ADMIN group
   c. <url-pattern>/user/*</url-pattern> are only authorized for users from USERS group
 
Restart the server.
 
10. Test the whole implementation by hitting the application at http://<host>:<port>/RoleBasedApp/. Provide a username and password for the resource you wish to access. Try to access a resource not authorized for the user which you used to logon. If you followed my database design and data, SUPER_ADMIN should have access to all resources, ADMIN only to user and admin resources, and USER only to user resources. Log out and log in with another user.



11. You can enable debug for Authorization and Authentication by going to WLS AdminConsole > Servers > <server_name> > Logging > General > Advanced and set Log File, Severity Level to Debug. Go to WLS AdminConsole > Servers > <server_name> > Debug > weblogic > security > atn/atz and enable DebugSecurityAtn and DebugSecurityAtz.

In the logs you can see our LoginModule messages:

####<22/06/2012 15h20min14s BRT> <Info> <CustomDBAuthenticationProvider> <XXXXXXXX> <AdminServer> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <weblogic> <> <> <1340389214511> <BEA-000000> <DatabaseAuthenticator: Verifying user:user@examples.com returned true>

####<22/06/2012 15h20min14s BRT> <Info> <CustomDBAuthenticationProvider> <XXXXXXXX> <AdminServer> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <weblogic> <> <> <1340389214677> <BEA-000000> <DatabaseAuthenticator: Groups for User user@examples.com found in Database: [USER]>

And the WLS Security Framework Authorization messages, allowing access to our user:

####<22/06/2012 15h20min14s BRT> <Debug> <SecurityAtz> <XXXXXXXX> <AdminServer> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <WLS Kernel> <> <> <1340389214755> <BEA-000000> <com.bea.common.security.internal.service.AccessDecisionServiceImpl.isAccessAllowed Resource=type=url>, application=RoleBasedApp, contextPath=/RoleBasedApp, uri=/user/userPage.jsp, httpMethod=GET>

####<22/06/2012 15h20min14s BRT> <Debug> <SecurityAtz> <XXXXXXXX> <AdminServer> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <WLS Kernel> <> <> <1340389214758> <BEA-000000> <Subject: 2
Principal = weblogic.security.principal.WLSUserImpl("user@examples.com")
Principal = weblogic.security.principal.WLSGroupImpl("USER")
>

####<22/06/2012 15h20min14s BRT> <Debug> <SecurityAtz> <XXXXXXXX> <AdminServer> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <WLS Kernel> <> <> <1340389214765> <BEA-000000> <Evaluate urn:oasis:names:tc:xacml:1.0:function:string-is-in(USER_ROLE,[Anonymous,USER_ROLE]) -> true>

####<22/06/2012 15h20min14s BRT> <Debug> <SecurityAtz> <XXXXXXXX> <AdminServer> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <WLS Kernel> <> <> <1340389214766> <BEA-000000> <primary-rule evaluates to Permit>

10 comments:

  1. This comment has been removed by the author.

    ReplyDelete
    Replies
    1. Hi, thank you for your comment, glad it helped you getting started on your provider. You can modify the DBAuthenticationProviderMBean.xml to add bean specific properties you can define for your own needs. Check out the code and the comments on the section 4d of this post.

      Delete
  2. Not found class in project examples.samples.wls.security.providers.authentication.mbeans.CustomDBAuthenticationProviderMBean; in DBAuthenticationProviderImpl.java
    Help please for build the project

    ReplyDelete
    Replies
    1. Have you added to your classpath in Eclipse (or your IDE) /wlserver_10.3/server/lib and /modules ?

      Also, take a look at item 3: "After the correct import, your project should look like the image below. Don't mind the CustomDBAuthenticationProviderMBean errors, we will get rid of them in the next steps."

      Delete
    2. I have configured the build.xml. As I compile with Eclipse? By clicking on option File -> Export -> Jar file. The jar and generates exports but with the errors mentioned in the MBean and is not created nor CustomDBAuthenticationProviderMBean.java WLS files, help please

      Delete
    3. Run the build.xml. In buil.xml Right click -> Run As -> Ant Build. But I genus the following errors:

      Buildfile: C:\Documents and Settings\user\My Documents\EclipseProjects\CustomDBAuthenticationProvider\build.xml
      clean:
      [delete] Deleting directory C:\Documents and Settings\user\My Documents\EclipseProjects\CustomDBAuthenticationProvider\build
      buildAndDeploy:
      [mkdir] Created dir: C:\Documents and Settings\user\My Documents\EclipseProjects\CustomDBAuthenticationProvider\build
      [copy] Copying 1 file to C:\Documents and Settings\user\My Documents\EclipseProjects\CustomDBAuthenticationProvider\build
      [copy] Copying 4 files to C:\Documents and Settings\user\My Documents\EclipseProjects\CustomDBAuthenticationProvider\build
      [java] java.lang.NoClassDefFoundError: and
      [java] Caused by: java.lang.ClassNotFoundException: and
      [java] at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
      [java] at java.security.AccessController.doPrivileged(Native Method)
      [java] at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
      [java] at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
      [java] at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
      [java] at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
      [java] Could not find the main class: and. Program will exit.
      [java] Exception in thread "main"

      BUILD FAILED
      C:\Documents and Settings\mchoto\My Documents\EclipseProjects\CustomDBAuthenticationProvider\build.xml:61: Java returned: 1

      Total time: 500 milliseconds

      Delete
    4. Apparently looking back to compile the same class but how to make the generated compiled before?

      Delete
  3. Hello Nice post on Security providers, Need one more help. I have to generate a custom security provider which needs to implement some function calls present in another jar file. I am able to build the jar(No compile time issues) but how can I configure the runtime dependencies?

    Could you please help/

    ReplyDelete
  4. Very nice post. It helped me in understanding how to implement DB authentication provider in weblogic. However, when I tried to run this sample in eclipse, I got compilation errors in CustomDBAuthenticationProviderMBeanImplBeanInfo file. This file is referencing weblogic.management.internal.mbean.BeanInfoBinder, BeanInfoHelper and BeanInfoImpl classes, but these files do not exist in weblogic.jar file.

    Can you point me how to solve this issue?

    ReplyDelete
  5. Hi Paulo Albuquerque ,
    really a wonderful post i helped me a lot to develop and understand the Custom authentication provider and Centralized login module. But how i can i integrate it with something perhaps Identity assertion . to achieve perimeter SSO in a clustered domain.
    please Help me.

    ReplyDelete