login button

HTTP Basic Authentication Mediator in WSO2 ESB with UserManager

Story :

Level : Project :

WSO2 ESB comes with a rich collection of useful mediators to filter, transform, route and manipulate messages. Developers can use these custom mediators to very easily add extra functionality. AuthenticationMediator is a custom mediator that can authorize users to access a Web service based on HTTP Basic authentication.

Introduction

AuthenticationMediator employs WSO2 UserManager to authenticate users. UserManager realms have the ability to connect new or existing user stores maintained in different technologies such as LDAP, Acegi or relational databases.

Features of AuthenticationMediator

  • Clients provide username/password using HTTP Basic authentication
  • Can authenticate users against user stores maintained in either LDAP, Acegi or RDBMS


Applies To

WSO2 ESB version 1.5
WSO2 UserManager version 0.5
Axis2 1.3


Table of contents

This tutorial shows how to install and run AuthenticationMediator, then it goes on to explain implementation details of the Mediator. If you are only interested in implementation details then you can jump to it straight away.


Background

Before we begin, we assume you know how to work with the WSO2 ESB, although you are not expected to know anything about the UserManager. This article will refer to the directory where WSO2 ESB is installed as <esb-home> - mimicking the WSO2 ESB documentation.

 

Installing and Running AuthenticationMediator

This is how you install AuthenticationMediator to your WSO2 ESB:

  1. Download authentication-mediator.zip from this page and extract it inside the <esb-home> directory. Make sure it isn't extracted to a sub directory, as the directory "authentication-mediator" must be directly under <esb-home>.
  2. Add all the jar files inside the <esb-home>/authenticate-mediator/lib directory to <esb-home>/webapp/WEB-INF/lib directory.
  3. We will modify the Synapse sample 150 configuration to test the Mediator. Therefore, first back up the file named <esb-home>/repository/conf/sample/synapse_sample_150.xml.

This tutorial deals with a client that sends username/password using pre-emptive HTTP basic authentication. The client is available inside <esb-home>/authenticate-mediator/auth-client.

WSO2 ESB creates the AuthenticationMediator when it encounters the <userStore> XML element inside the Synapse Configuration. Therefore, we will edit the <esb-home>/repository/conf/sample/synapse_sample_150.xml, as shown in Step #4 below. The configuration XML snippet also states the type of user's store and how to connect to it. For example, if the user store is LDAP, the XML will state how to connect to it and authenticated users. When creating the AuthenticationMediator the relevant realm will also be created.

Connecting to a RDBMS User Store

  1. Go to <esb-home>/authentication-mediator/sample-db and give the following command:
  2. ant create-db

    The ant script will create an Apache Derby database inside <esb-home>/authentication-mediator/sample_db/AuthenticationMediatorUsers/USER_STORE. Copy the USER_STORE directory into <esb-home>/webapp/WEB-INF/classes/conf directory. It will contain the following users:

    User Name Password
    john doe
    alice alice
    bob bob
    chris chris

  3. Add the following to the <esb-home>/webapp/WEB-INF/classes/conf/derby.properties file:
  4. derby.user.tintin=snowy
    Derby is configured inside ESB to use "Built-In authentication scheme". Therefore, all derby connection username/passwords must be in the file. The connection name for our sample user database is "tintin" and password "snowy". This step is not needed if you are using some other JDBC driver other than Derby.

     

  5. Start the ESB with sample configuration 150.
  6. sh wso2-esb.sh -sample 150
  7. Go to the ESB management console and click on the Configuration tab. Edit the configuration to include a <inSequence> with the following XML snippet. This element should be at the same level as <syn:outSequence>. Then click update.
  8. <syn:inSequence>
    <syn:userStore>
    <syn:realmClass>org.wso2.usermanager.custom.jdbc.JDBCRealm</syn:realmClass>
    <syn:realmParameters>
    <syn:parameter name="UserTable">sample_user</syn:parameter>
    <syn:parameter name="UserNameColumn">username</syn:parameter>
    <syn:parameter name="UserCredentialColumn">password</syn:parameter>
    <syn:parameter name="ConnectionURL">jdbc:derby:USER_STORE</syn:parameter>
    <syn:parameter name="DriverName">org.apache.derby.jdbc.EmbeddedDriver</syn:parameter>
    <syn:parameter name="ConnectionUserName">tintin</syn:parameter>
    <syn:parameter name="ConnectionPassword">snowy</syn:parameter>
    </syn:realmParameters>
    </syn:userStore>
    </syn:inSequence>

  9. Go to <esb-home>/samples/axis2Server. Start the sample Axis2 server by running the axis2server script.
     
  10. Go to <esb-home>/authentication-mediator/auth-client. Run the client by typing the following.
  11. ant stockquote -Daddurl=http://localhost:8080/soap/StockQuoteProxy -Dusername=alice -Dpassword=alice
  12. If you run the client by giving the following data, it must fail, since the password is incorrect.
  13. ant stockquote -Daddurl=http://localhost:8080/soap/StockQuoteProxy -Dusername=alice -Dpassword=hora

In this manner, you could also connect to any existing database using a standard JDBC driver. All you have to do is change the configuration parameters.


Troubleshooting Connecting to a RDBMS User Store

Connecting to a LDAP User Store 

Before continuing you must have a LDAP server running on your local machine or in a server accessible to you.

 

  1. Start the ESB by typing the following command. 
  2. sh wso2-esb.sh -sample 150
  3. In the  ESB management console's Configuration tab, edit the configuration to have a <inSequence>. Following is a sample XML snippet for LDAP. Click on update. 
  4. <syn:inSequence>
    <syn:userStore>
    <syn:realmClass>org.wso2.usermanager.custom.ldap.LDAPRealm</syn:realmClass>
    <syn:realmParameters>
    <syn:parameter name="ConnectionUrl">ldap://localhost:389</syn:parameter>
    <syn:parameter name="ConnectionName">cn=root,dc=wso2,dc=com</syn:parameter>
    <syn:parameter name="ConnectionPass">secret</syn:parameter>
    <syn:parameter name="UserPattern">uid={0},ou=People,dc=wso2,dc=com</syn:parameter>
    </syn:realmParameters>
    </syn:userStore>
    </syn:inSequence>
  5. Go to <esb-home>/samples/axis2Server. Start the sample Axis2 server
  6. Go to <esb-home>/authentication-mediator/auth-client. Run the client as follows:
  7. ant stockquote -Daddurl=http://localhost:8080/soap/StockQuoteProxy -Dusername=alice -Dpassword=alice


Connecting to a Acegi user store

Download Acegi 1.0.6 release from here and unzip it. We will call this folder <acegi-home>

  1. Add <acegi-home>/acegi-security-1.0.6.jar to <esb-home>/webapp/WEB-INF/lib directory 
  2. Start the ESB with sample configuration 150.
  3. sh wso2-esb.sh -sample 150
  4. Unzip the <acegi-home>/acegi-security-samples-tutorial-1.0.6.war file. For the purpose of testing, copy the applicationContext-acegi-security.xml and users.properties files from  <acegi-home>/acegi-security-samples-tutorial-1.0.6/WEB-INF/ directory into the <esb-home> directory.  Edit userDetailsService in applicationContext-acegi-security.xml file to be as follows. (If you already have an Acegi store, you can skip this step but remeber to enter the correct values for the Synapse configuration in the next step).
  5. <bean id="userDetailsService" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">

    <property name="userProperties">

    <bean class="org.springframework.beans.factory.config.PropertiesFactoryBean">

    <property name="location" value="users.properties"/>

    </bean>

    </property>

    </bean>
  6. Edit the configuration to have a <inSequence> as in the following XML snippet. For the
    AuthenticationProviderBeanMappingFile parameter, the relative file path must be given:
  7. <syn:inSequence>
    <syn:userStore>
    <syn:realmClass>org.wso2.usermanager.custom.acegi.AcegiRealm</syn:realmClass>
    <syn:realmParameters>
    <syn:parameter name="AuthenticationProviderBeanMappingFile">applicationContext-acegi-security.xml</syn:parameter>
    <syn:parameter name="AuthProviderId">daoAuthenticationProvider</syn:parameter>
    </syn:realmParameters>
    </syn:userStore>
    </syn:inSequence>
  8. Go to <esb-home>/samples/axis2Server. Start the sample Axis2 server..
  9. Go to <esb-home>/authentication-mediator/auth-client. Run the client with username/password.
  10. ant stockquote -Daddurl=http://localhost:8080/soap/StockQuoteProxy -Dusername=scott -Dpassword=wombat

     

Implementing the AuthenticationMediator

In this section we discuss implementation details of AuthenticationMediator briefly. We use the interface trio described here - Mediator, Factory and Serializer.

When mediator() method of AuthenticationMediator is called, it reads username/password from HTTP headers and the authenticate() method of the realm is called to provide authentication. If the user is not authenticated, an exception is thrown and the service will not be accessible.

Axis2MessageContext axis2smc = (Axis2MessageContext) synCtx;
            org.apache.axis2.context.MessageContext axis2MessageCtx =
            axis2smc.getAxis2MessageContext();
            Map tmp = (Map)axis2MessageCtx.getProperty(org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS);
            String authString = (String)tmp.get("Authorization");
            String username = null;
            String password = null;

            if (authString != null) {
                authString = authString.trim();
            }
            if (authString.startsWith("Basic ")) {
                authString = new String(Base64.decode(authString.substring(6)));
                int i = authString.indexOf(':');
                if (i == -1) {
                    username = authString;
                } else {
                    username = authString.substring(0, i);
                }

                if (i != -1) {
                    password = authString.substring(i + 1);
                    if (password != null && password.equals("")) {
                        password = null;
                    }
                }
            }
            
            if(!realm.getAuthenticator().authenticate(username, password)){
                handleException("Invalid Username/Password!", synCtx);
            }

When the createMediator() method of the AuthenticationMediatorFactory is called, the Realm is created and set to the AuthenticationMediator.

Class clazz = Class.forName(realmClassName);
            Realm realm = (Realm) clazz.newInstance();
            Object configBean = realm.getRealmConfiguration();
            .................
   	    /* 
               Populate configBean by reading name-value pairs given  
	       by parameter elements inside the <userStore> 
               of the Synapse Configuration.
	       Using Java Reflection.
	    */
            ........
            ...
            realm.init(configBean);

            AuthenticationMediator mediator = new AuthenticationMediator();
            mediator.setRealm(realm);
            return mediator;

The XML snippet given in the Synapse definition is used for creating and configuring the Realm inside the Mediator Factory. Since Java Reflection is used for populating the configuration of the Realm, any custom Realm can be loaded into the AuthenticationMediator.

For example,

<syn:userStore>
    <syn:realmClass>org.wso2.usermanager.custom.jdbc.JDBCRealm</syn:realmClass>
    <syn:realmParameters>
        <syn:parameter name="UserTable">users</syn:parameter>
    </syn:realmParameters>
</syn:userStore>

The method called for the above parameter is setUserTable() in the configBean of the Realm.

 

Conclusion

 

WSO2 ESB is a powerful and extensible enterprise service bus. UserManager is a flexible and extensible library that can be configured to connect user stores belonging to different technologies. In the same way, developers can add functionality to the WSO2 ESB by writing Mediators. New Realms can be written enabling UserManager to connect to many different types of user stores. AuthenticationMediator uses Java Reflection technology to populate realms by reading the XML snippet. Therefore, AuthenticationMediator is not restricted to the Realms mentioned above.

 

Author

Dimuthu Leelarathne is a Senior Software Engineer at WSO2. She is a committer of the Apache Software Foundation.

dimuthul at wso2 dot com

AttachmentSize
authentication-mediator.zip129.01 KB
0
No votes yet
Tags :