Saturday, February 8, 2014

Securing your Web Service with OAuth2 using WSO2 IS



Introduction


Web applications sometimes need access to certain user information in another web service. In such a case how do you get your app authorized, on behalf of user, against that web service? Years ago this problem was solved by user giving their credentials to web application and then the web application uses them to authenticate itself against the web service. But, in user’s perspective, giving away their credentials to another web application to log in as himself, is not a good story, because with user credentials, web application gets the full control of user account until user changes their password. People needed a solution for this, and they came up with a variety of solutions such as Google AuthSub, AOL OpenAuth, Yahoo BBAuth, Upcoming api, Flickr api, Amazon Web Services api [1] etc. But there were a lot of differences between each of them, and so people needed a standard for this. This is where OAuth came into play.

What is OAuth?


OAuth is an open protocol which enables an application to access certain user information or resource from another web service, without giving user credential for the web service to the web application. For example, a user needs to allow a third party application to change his twitter profile picture. When OAuth is used for authorization, it allows 3rd party application to change user’s profile picture after user authorize it to do so without giving credentials directly to the web application.

How it works


There are several Grant Types in OAuth 2. Some widely used Grant Types are Authorization Code, Implicit, Client Credentials, Password, Refresh Token etc. Depending on the Grant Type, there are different ways, in which we can use OAuth for applications. We will be discussing about each of these types later on this post. But in following example, we will be using Authorization Code Grant Type. 

Before step 1, Consumer App is registered with Identity Provider (IDP) and IDP issues a Client ID and a Client Secret for the client. In step 1, Consumer App sends the authorization request to IDP. That request contains Client ID, scope of authorization and callback URL. Here, the scope is used to specify for which level the Consumer App needs authorization. If we go back to earlier example, the 3rd party application only needed authorization to change user’s profile picture. So we should not allow anything more than that, for the Consumer App. This is what’s represented by ‘scope’ of the authorization. Callback URL is what’s used by IDP to contact the Consumer App back. Once the authorization request is granted (in step 4) IDP contacts the Consumer App through this URL. In step 2, IDP asks user to authenticate himself and authorize the Consumer App for the given scope. In step 3, user, after authenticating himself first, reviews the authorization request’s scope and accepts it. In step 4, IDP contacts the Consumer App through its callback URL and sends the authorization code. This authorization code, with Client Secret, can be used to obtain an Access Token to access the particular resource. That’s what happens in step 5. In step 6, IDP sends an Access Token to the Consumer App. In step 7, Consumer App uses that Access Token to request access to the particular resource from resource server. In step 8, resource server contacts IDP to get the Access Token verified, and in step 9, IDP sends the verification response back to the resource server. Then, resource server allows the Consumer App to access the resource under given scope. 

OAuth for your web service/application


In the example we discussed earlier, an identity provider is integrated with Twitter so that external application can access it on behalf of its users. Now, if you want to secure your web service using OAuth, how do you that? You need an identity provider for that. WSO2 Identity Server is such an identity provider which provides a simple and easy way to get this done with few steps.



Let’s discuss those steps using an example. In this example, we are going to secure a REST service using OAuth. The rest service we will be using is YouTube search service. Here, WSO2 ESB acts as the resource server.

Setting Up the Environment


In this example, IPs of host machines of each server is as follows.

WSO2 ESB 4.8.1 : 10.100.0.64
WSO2 IS 4.6.0 and Tomcat: 10.100.0.65


We will be using Playground2 webapp as the Consumer App. It’s using Apache Amber OAuth2 client to communicate with WSO2 IS, but you can use any OAuth client for your application. You can download its complete maven project here. After downloading the war file, host it in Tomcat server. Then we will be able to access it via http://10.100.0.65:8080/playground2

Now let’s configure WSO2 ESB. Here we will be using an API element to configure REST service endpoint. We need to create a custom handler for API element to achieve what we discussed in step 8 and 9. This handler will communicate with WSO2 IS and get the Access Token verified, once the Consumer App sends the resource access request, with Access Token, to ESB. 

Handler class is as follows. Complete maven project can be downloaded from here.

This handler reads OAuth2TokenValidationService URL of WSO2 IS and admin credentials to access that service, from axis.xml of ESB. Then it calls this admin service and pass the scope of the authorization with Access Token. Then WSO2IS will verify them and inform the ESB back about verification status.

Then build the handler project ($ mvn clean install) and get the handler.jar created. Then put it in $ESB_HOME/repository/components/lib.

Add following configs to $ESB_HOME/repository/conf/axis2/axis2.xml


Restart ESB and go to Manage > Service Bus > Source View

Add following API Element config.



In this API element we configure backend REST service which needs to be secured with OAuth, and the handler class we implemented. In this example, we have to remove ‘Authorization’ header of the incoming message, which is used to authenticate for the service exposed by ESB, from message before sending it out to backend service, because unless YouTube tries to validate this token and gives an error message saying ‘Invalid Token’.

Now let’s configure WSO2 Identity Server.

First, let’s register this Consumer App in WSO2 Identity Server. Download and start WSO2IS. After logged in, go to Main > Manage > OAuth and click on Register New Application.



For this example, we are using OAuth version 2. Give any name for the application. The callback URL of our application is http://localhost:8080/playground2/oauth2client. There are multiple grant types supported by WSO2 IS. We will be discussing them individually, later in this post. 

Once the app is added, its will be listed as follows.


Now Click on the application name and following page will come up.



When the app was added, a Client ID and a Client Secret are generated for the application. Consumer Application should have them with it. Client ID is public where Client Secret is a secret which should not be exposed to public. Consumer app should also know Authentication and Access Token endpoints of IDP (i.e. WSO2 IS in this case). 

Go to http://l10.100.0.65:8080/playground2 and click on the search image.



In this example, we will be using ‘Authorization Code’ Grant Type. Now we can give Client ID and authorization endpoint of IDP to the Consumer App. Here we are sending our initial request (step 1) to IDP’s authorization endpoint. 

Then IDP (WSO2 IS) shows following page to the user.


Once we click Continue, It will ask to authenticate the user. (Step 2)

After we logged in, it will ask us to review and authorize Consumer App’s authorization request. Then we approve the request. (Step 3)


Once we approved the request, Consumer app get’s the authorization code. (Step 4)


Now Consumer App can request for the Access Token. In this request it needs to specify Authorization Code and Client Secret. This request is sent to the Access Token endpoint of the IDP. (Step 5)


Then the IDP will send an Access Token. (Step 6) Now Consumer app can send the request to ESB with Access Token. (Step 7) In this example, we call ESB’s ‘YouTubeSearch’ service, which we created earlier. That service eventually calls YouTube Search service.

Corresponding curl command for this is like this.

curl -v -X GET -H “Authorization: Bearer <ACCESS_TOKEN>” http://10.100.0.64:8280/search

Once this request hits the ESB, the handler we deployed will call IDP (i.e. WSO2 IS) and get the Access Token verified. (Step 8 and 9) Then ESB will call backend REST service and get response back to the Consumer App. (Step 10, 11 and 12) 




Grant Types Supported by WSO2 Identity Server

Identity Server supports following grant types.

Authorization Code

This is the type we discussed throughout the post, where IDP issues an Authorization code once the Consumer app’s authorization request is approved by the user.

Implicit

In this type, client secret is not involved. This is mostly used for mobile apps and web browser based apps (javascript apps etc.) where client secret cannot be kept in secret. In this method, once the user authorizes the Consumer App’s authorization request, app gets the Access Token directly.

Password

In this type, user’s credentials are sent with initial request. This seems to contradict with purpose of having OAuth, which is avoiding giving away your password to a 3rd party application. But actually it doesn’t, because this method is supposed to be used by the applications which owned by the resource server itself, but not any other 3rd party.

Client Credentials

Resource owner (i.e. user) is not involved in this method. Here, Consumer app uses its Client ID and Client Secret to get an Access Token. This method is supposed to be used when app needs to access its own data rather than user’s protected data.

Refresh Token

In this method, IDP provides a Refresh Token (with Access Token), which Consumer app can use to get a new Access Token once the current Access Token is expired. So user doesn’t have to involve to authorize every time the Access Token expires.

SAML

In this grant type, Consumer application can present an SAML assertion to IDP, and get an Access Token, without requiring user to authenticate again. This is somewhat similar to Refresh Token type.

Conclusion

You may want to allow 3rd party apps to access your web service to do particular tasks on behalf of users. So, apps need a way to authenticate themselves against your web service. Asking your users to simply give their passwords to 3rd party apps is not a solution, because it allows those apps to do anything that user can do, regardless of what user really wants the app to do behalf of themselves. In such a situation, OAuth is a really good solution which does not compromise user’s account’s security, because in OAuth user doesn’t have to give away their credentials to 3rd party apps. To secure your web service with OAuth, you don’t have to implement it yourself from the scratch. WSO2 Identity Server (WSO2 IS) is an Identity Provider which does that for you with few simple steps. Once you configured your web service with WSO2 ESB, 3rd party applications only have to register themselves in WSO2 IS. And you are ready to market. 


Downloads


8 comments:

  1. Hi Bhathiya,
    Playground2.war and Handler-1.1.0.jar source code link is not working

    ReplyDelete
    Replies
    1. Thanks for letting me know. I updated the link, but I don't think those will work with the latest versions of WSO2 Identity Server.

      Delete
  2. Hi Bhathiya

    I am unable to update axis2.xml file when i try to make any changes and restart the service the axis2.xml file is getting back to its original code .

    ReplyDelete
    Replies
    1. I'm assuming you are using one of the latest versions of IS. They have a new config model. Please check documentation of the corresponding version.

      Delete
  3. Hi Bhathiya,

    Thanks for the reply . We are using Api manager 3.0.0 we followed the document but still we are not able to make permanent changes to the axis2.xml files .

    ReplyDelete
    Replies
    1. Did you use the deployment.tolml? If yes, please create a question in stackoverflow with wso2am tag.

      Delete
  4. Hi Bhathiya,

    No i have not used the deployment.tolml. Can you tell me what changes need to me made in that .

    ReplyDelete
    Replies
    1. Plz create a question in stackoverflow with wso2am tag. explain the issue and mention which doc you followed.

      Delete