HTTP Basic Authentication Mediator in WSO2 ESB with UserManager

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.
Date: Sun, 6th Jan, 2008
Level: Advanced
Reads: 2875 Comments: 0 | Login or register to post comments
Dimuthu Leelarathne
Tech Lead
WSO2
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 Installing and Running AuthenticationMediator Connecting to a RDBMS User Store Connecting to a LDAP User Store Connecting to a Acegi user store Implementing the AuthenticationMediator Conclusion 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: 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>. Add all the jar files inside the <esb-home>/authenticate-mediator/lib directory to <esb-home>/webapp/WEB-INF/lib directory. 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 Go to <esb-home>/authentication-mediator/sample-db and give the following command: 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 Add the following to the <esb-home>/webapp/WEB-INF/classes/conf/derby.properties file: 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. Start the ESB with sample configuration 150. sh wso2-esb.sh -sample 150 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. <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> Go to <esb-home>/samples/axis2Server. Start the sample Axis2 server by running the axis2server script.   Go to <esb-home>/authentication-mediator/auth-client. Run the client by typing the following. ant stockquote -Daddurl=http://localhost:8080/soap/StockQuoteProxy -Dusername=alice -Dpassword=alice If you run the client by giving the following data, it must fail, since the password is incorrect. 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 If you are using a Derby database driver, check to confirm that you have updated derby.properties file with the username/password as in the previous step (step2). If you are using a driver other than Derby, check to confirm that it is added to the classpath Check for version compatibilities with the database and the version of the driver you are using. Different database drivers require different patterns of connection URLs. Make sure the data given is correct. 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. Start the ESB by typing the following command.  sh wso2-esb.sh -sample 150 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.  <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> Go to <esb-home>/samples/axis2Server. Start the sample Axis2 server Go to <esb-home>/authentication-mediator/auth-client. Run the client as follows: 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> Add <acegi-home>/acegi-security-1.0.6.jar to <esb-home>/webapp/WEB-INF/lib directory  Start the ESB with sample configuration 150. sh wso2-esb.sh -sample 150< 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). <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> Edit the configuration to have a <inSequence> as in the following XML snippet. For the AuthenticationProviderBeanMappingFile parameter, the relative file path must be given: <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> Go to <esb-home>/samples/axis2Server. Start the sample Axis2 server.. Go to <esb-home>/authentication-mediator/auth-client. Run the client with username/password. 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
Hot Topic
Hot
Topic

Google Gadgets are a nice way to develop user interfaces for distributed services. The fact that they can be hosted anywhere over a network, not necessarily in the very portal server they eventually run in makes them re-usable and allows users to quickly...

Mini Banners
WSO2Con 2010
Latest Webinar
In this webinar we'll share the range of concerns we've heard from the industry, and survey some of the new and sometimes subtle types of lock-in associated with cloud technologies.
Wednesday, 8 September, 10.00 AM (PDT)