Monday, March 5, 2012

Implementing SCIM with WSO2 Charon - Part III

In this post, lets look at how to implement few use cases of SCIM with WSO2 Charon.
You may need to refer to my previous posts on SCIM and Charon to get an overview of them.

Being the third post on Charon, lets continue looking at it in the top down approach.

Part II described the composition of Charon-Impl. which is the SCIM service provider reference implementation shipped with Charon. It is a Apache Wink based webapp that utilizes Charon-Core and Charon-Utils to expose a SCIM REST API for identity provisioning operations.

This post will demonstrate the following capabilities of Charon according to SCIM spec.

1). Create user
2). Create group
3). List Users

Setting up SCIM Service Provider with Charon-Impl:

Download CharonDemoApp from M1 Distribution and deploy it in an application server like Apache Tomcat and start the server.
As shown in the diagram of the part-II post, User Resource and Group Resource are now exposed based on Apache Wink JAX-RS implementation, via following URLS.
  • User Resource: http://localhost:8080/charonDemoApp/scim/Users
  • Group Resource: http://localhost:8080/charonDemoApp/scim/Groups
    Sample use cases:

    1. Creating a user.. 
    This demonstrates how a SCIM consumer creates (provision) a User in SCIM service provider via a REST call in which User attributes are carried as a JSON encoded string.

    Client code :  SCIM client uses the previously registered credentials to authenticate the request.
    package org.wso2.charon.samples.user.sample01;
    
    import org.apache.wink.client.ClientConfig;
    import org.apache.wink.client.ClientWebException;
    import org.apache.wink.client.Resource;
    import org.apache.wink.client.RestClient;
    import org.apache.wink.client.handlers.ClientHandler;
    import org.wso2.charon.core.client.SCIMClient;
    import org.wso2.charon.core.exceptions.CharonException;
    import org.wso2.charon.core.objects.User;
    import org.wso2.charon.core.schema.SCIMConstants;
    import org.wso2.charon.samples.utils.CharonResponseHandler;
    import org.wso2.charon.samples.utils.SampleConstants;
    import org.wso2.charon.utils.authentication.BasicAuthHandler;
    import org.wso2.charon.utils.authentication.BasicAuthInfo;
    
    public class CreateUserSample {
    
        //user details
        public static final String USER_NAME = "hasinig";
        public static final String EXTERNAL_ID = "hasini@gmail.com";
        public static final String[] EMAILS = {"hasini@gmail.com", "hasini@wso2.com"};
        public static final String DISPLAY_NAME = "Hasini Gunasinghe";
        public static final String PASSWORD = "dummyPW";
        public static final String LANGUAGE = "Sinhala";
        public static final String PHONE_NUMBER = "9077657623";
    
        public static void main(String[] args) {
    
            try {
                //create SCIM client
                SCIMClient scimClient = new SCIMClient();
                //create a user according to SCIM User Schema
                User scimUser = scimClient.createUser();
                scimUser.setUserName(USER_NAME);
                scimUser.setExternalId(EXTERNAL_ID);
                scimUser.setEmails(EMAILS);
                scimUser.setDisplayName(DISPLAY_NAME);
                scimUser.setPassword(PASSWORD);
                scimUser.setPreferredLanguage(LANGUAGE);
                scimUser.setPhoneNumber(PHONE_NUMBER, null, false);
                //encode the user in JSON format
                String encodedUser = scimClient.encodeSCIMObject(scimUser, SCIMConstants.JSON);
                //create a apache wink ClientHandler to intercept and identify response messages
                CharonResponseHandler responseHandler = new CharonResponseHandler();
                responseHandler.setSCIMClient(scimClient);
                //set the handler in wink client config
                ClientConfig clientConfig = new ClientConfig();
                clientConfig.handlers(new ClientHandler[]{responseHandler});
                //create a wink rest client with the above config
                RestClient restClient = new RestClient(clientConfig);
                //create resource endpoint to access User resource
                Resource userResource = restClient.resource(SampleConstants.USER_ENDPOINT);
    
                BasicAuthInfo basicAuthInfo = new BasicAuthInfo();
                basicAuthInfo.setUserName(SampleConstants.CRED_USER_NAME);
                basicAuthInfo.setPassword(SampleConstants.CRED_PASSWORD);
    
                BasicAuthHandler basicAuthHandler = new BasicAuthHandler();
                BasicAuthInfo encodedBasicAuthInfo = (BasicAuthInfo) basicAuthHandler.getAuthenticationToken(basicAuthInfo);
    
    
                //TODO:enable, disable SSL. For the demo purpose, we make the calls over http
                //send previously registered SCIM consumer credentials in http headers.
                String response = userResource.
                        header(SCIMConstants.AUTHORIZATION_HEADER, encodedBasicAuthInfo.getAuthorizationHeader()).
                        contentType(SCIMConstants.APPLICATION_JSON).accept(SCIMConstants.APPLICATION_JSON).
                        post(String.class, encodedUser);
    
                //decode the response
                System.out.println(response);
            } catch (CharonException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            } catch (ClientWebException e) {
                System.out.println(e.getRequest().getEntity());
                System.out.println(e.getResponse().getMessage());
                e.printStackTrace();
            }
        }
    }
    
    
    Request-Response: Please click on the below image to see it in full size. After successful creation of the user;
    - service provider responds with 201-Created response code and
    - includes newly created user in response body.
    - Representation in response contains an additional attributes 'id', 'created date', 'last modified date' etc which is assigned by the SP and
    - the "Location" header contains the unique URI of the created user resource.

    2. Create Group..(From SCIM spec)
    Following request/reponse is captured when creating a group with two exisiing users in the system.

    Request-Response: Please click on the below image to see it in full size.
    Server responds with 200 OK including group resource in the body encoded in JSON.

    3. List Users
    Following request/response illustrates a SCIM consumer call to list all the users.
    Server responds with two user entries existing in its user store.

    Note:
    1. Libraries for sample client code:
    You can find the required libraries to run the WSO2 Charon samples from here.
    2. Sample source code can be found in the M1 distribution linked above.
    3. As illustrated by above sample use case, SCIM consumer will be able to perform identity provisioning operations with any SCIM service provider in a unified way by just changing the resource URLs - which avoids the need of developping multiple connectors to integrate with different cloud providers.

    Saturday, February 25, 2012

    Timestamp in WS-Security to mitigate replay attacks

    How replay attacks can be harmful:
    When sensitive information is exchanged or critical transactions are performed over the network, we need to secure the communication.

    General requirements of secure message communication are authentication, integrity, confidentiality and non-repudiation.

    One can achieve above requirements through transport level security or message level security mechanisms such as security tokens, signature and encryption. 

    Even though you adopt above mechanisms alone, to secure a message, one can intercept a secured message on the wire and resend the message repeatedly to the same endpoint and cause damages - unless there is a mechanism to verify the validity/originality of the message.

    For an example:
    - user logs into online banking and performs a transaction.
    - an attacker traces the messages exchanged during the process.
    - attacker resends the sequence of messages involved with login step, to login and steal money from the bank account.

    Timestamp in WS-Security:
    Therefore, it is important to validate the freshness of a message before performing any operation that the message invokes. This validation can be performed either in the business logic or security processing layer of the platform in a generic manner.

    If your soap message processing engine supports WS-Security to achieve message level security; Timestamp element defined there helps verifying the message validity in terms of time.

    (WS-Security is a spec that defines a framework to enable security related information -as specified by mechanisms such as XML security, XML signature etc- be embedded in the SOAP message.)

    Timestamp element allows the sender to express the creation and expiration times of the security semantics of the message - using which recipient can validate the freshness of the security semantics of the message to mitigate replay attacks.

    Following is the schema of Timestamp element.
    
     ...
     ...
     ...
    
    
    Few points to be noted are:
    • Time references must be in UTC time.
    • Time references are recommended to be in xsd:dateTime format, if in any other format is used, it should be specified in ValueType attribute.
    • Spec doesn't mention any mechanism for synchronizing the time between sender and recipient - but specifies that this should be addressed.
    • Timestamp element should be signed in order to prevent it being forged.
    • Another sub element that may present in Timestamp element is "wsu:received"  which can be included by an intermediary.
    • Only one global timestamp element can be present in one security header.
    Following is an actual Timestamp element extracted from a secured message:
    
         2011-09-24T12:11:41.331Z
         2011-09-24T12:16:41.331Z
    
    
    Above what we discussed is the theory part related to Timestamp as defined in the spec. Now lets see how it is being utilized and processed in an actual implementation - by referring to Rampart and WSS4J.
     
    Rampart & WSS4J:
    Rampart is the Axis2 module which introduces security processing handlers to inflow and out flow of the Axis2 SOAP processing engine. Rampart internally utilizes WSS4J which implements the support for WS-Security.

    Following are the rampart configuration parameters which allows user to configure and control Timestamp handling in Rampart and WSS4J. (Applies to Rampart 1.6.2 or above)
    
          ...
          true
          
          300
          300
          false
          ...
    
    
    • timestampprecisioninmilliseconds : whether the precession of timestamp reference is in milliseconds. This is a configuration parameter passed to WSS4J, when creating WSSConfig.
    • timestampttl : Validity period of the message as decided by the sender of the message. This is used in Rampart level to calculate "expires" time reference. Default value is 300 seconds. 
    • timestampmaxskew : Specifies the maximum tolerance limit for the clock skew between sender and recipient. As specified by WS-Security spec, it should be taken into consideration that renders and recipients clocks may not be in synchronized and proper measures should be taken to avoid it. This is a rampart level config parameter and the default value is 300 seconds.
    • timestampstrict :  This instructs rampart whether to enable timestamp validation at WSS4J level or not. By default - this is set to false. i.e: Timestamp validation happens in PolicyBasedResultsValidator of Rampart.
    How Timestamp is created:
    RampartSender is the handler introduced by Rampart for security processing of the out flow of Axis2.

    In the process of securing the outgoing message according to the defined security policy, BindingBuilder adds Timestamp element to the security header.

    Following is how 'created' and 'expires' time references of Timestamp are derived:
    • created = current time
    • expires = created(in millis) + timestampttl*1000
    How Timestamp is validated:
    RampartReceiver is the handler introduced by Rampart for security processing of the inflow of Axis2.

    In the process of validating the security of the incoming message, both WSSecurityEngine(in WSS4J) and PolicyBasedResultsValidator(in Rampart) validates Timestamp in the security header.

    WSS4J only checks whether the 'expires' time reference is before the current time of the receiver, to validate timestamp.

    Rampart - on the other hand verifies timestamp taking timestampmaxskew also into consideration and validates against both 'created' and 'expires' time references.

    Timestamp is invalid if:
    • current time < [created - (timestampmaxskew*1000)]  (in millis)
    • current time > [created + (timestampmaxskew*1000)] (in millis)
    Because of the consistent way timestamp is verified in Rampart level considering both created and expired, the validation at the WSS4J is disabled by default with timestampstrict set to false - which was introduced with the fix for the issue RAMPART-357.

    Other ways to avoid replay attacks:
    According to the above logic of validating Timestamp, it is considered valid during the time period:
    from (created - timestampskew) to (expires + timestampskew)
    - which means replay attacks made during that period is not detected if any other mechanism is not adopted to detect and avoid replay attacks.

    Some other mechanisms to avoid replay attacks are:
    1. Using session keys.
    2. Using one time passwords.
    3. Using nonce value.

    References:
    • Understanding WS-Security http://msdn.microsoft.com/en-us/library/ms977327.aspx

    Tuesday, February 14, 2012

    Implementing SCIM with Charon - Part II

    We had a look at an overview of WSO2 Charon in my previous post.

    Today lets go through a brief introduction of the module : Charon-Deplyment, which is the reference implementation of SCIM service provider that is shipped with Charon.

    This will illustrate how any concrete implementation of a SCIM service provider can make use of Charon-Core (the SCIM API) with Charon-Utils (optional). So being the second post on Charon, this will continue the top down approach of looking at it.

    As we got to know from the introductory post on SCIM, the protocol defines a REST API for user identity provisioning operations.

    Hence SCIM service provider needs to be a RESTful web application. In an earlier post, I have noted down the characteristic of REST - which is an architectural style of building networked applications.

    There are several ways to implement a REST style based applications - such as Servlets and JAX-RS based frameworks.

    In the reference implementation of Charon-SCIM servervice provider, we have selected the latter approach since JAX-RS hides underlying HTTP handling and binds the servlets nicely to individual methods in the Java classes using annotations.  Annotations can also dynamically extract information from HTTP requests and map application-generated exceptions to HTTP response codes.

    Out of the JAX-RS implementations, Apache-Wink was selected since it looks promising to cater our requirements.

    The Charon-Impl module creates an Apache-Wink based web application which can be deployed in an application server like Tomcat and which acts as a SCIM service provider.

    Following is a deployment diagram of Charon-SCIM service provider (the web application provided by Charon-Impl module). It also gives a high level idea on how Charon-Core and Charon-Utils modules will be utilized.

    As this diagram of the reference implementation illustrates, a SCIM service provider can be developed using any REST implementation and SCIM-defined resources can be exposed utilizing the API provided by Charon-Core.

    On the other hand, SCIM Consumers can also be implemented using the client API of Charon-Core.

    More posts to be followed...