0% found this document useful (0 votes)
286 views11 pages

WSO2 Inc - Securing Your Web Service With OAuth2 Using WSO2 Identity Server - 2014-03-28

Oauth2 protocol

Uploaded by

viaan1990
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
286 views11 pages

WSO2 Inc - Securing Your Web Service With OAuth2 Using WSO2 Identity Server - 2014-03-28

Oauth2 protocol

Uploaded by

viaan1990
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 11

Published on WSO2 Inc (http://wso2.

com)
Home > Stories > Securing your Web Service with OAuth2 using WSO2 Identity Server
Securing your Web Service with OAuth2 using
WSO2 Identity Server
By bhathiya.wso2.com
Created 2014-02-11 00:00
Introduction
Web applications sometime need access to certain user information in another web service. In such a
case, how would you get your app authorized, on behalf of the user, against that web service? Years ago
this problem was solved by users giving their credentials to the web application and then the web
application uses them to authenticate itself against the web service. However, in the user?s perspective,
giving away their credentials to another web application to log in as him/herself, is not a good story
because, with user credentials, the web application gains full control of the user account until the user
changes the password. People needed a solution, 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 therefore, there was a need to
standardize this. This is where OAuth came into play.
What is OAuth?
OAuth is an open protocol that enables an application to access certain user information or resources from
another web service, without giving the user?s credentials for the web service to the web application, e.g. a
user needs to allow a third-party application to change his Twitter profile picture. When OAuth is used for
authorization, it allows the third-party application to change the user?s profile picture after the user
authorizes it to do so without giving credentials directly to the web application.
How does it work?
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 in this article. In the following example, we use Authorization Code Grant Type.
Before Step 1, the Consumer App is registered with Identity Provider (IDP) and IDP issues a Client ID and
a Client Secret for the client. In Step 1, the 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 the earlier example, the third-party
application only needs authorization to change the 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 the user to
authenticate himself and authorize the Consumer App for the given scope. In Step 3, the 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, the
Consumer App uses that Access Token to request access to the particular resource from the resource
server. In Step 8, the resource server contacts IDP to get the Access Token verified, and in Step 9, IDP
sends the verification response back to the resource server. Thereafter, the resource server allows the
Consumer App to access the resource under the 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 this purpose. WSO2 IS is such an identity provider that
provides a simple and easy way to get this done in just a 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 used is YouTube search service. Here, WSO2 Enterprise Service Bus
(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. Playground2 web app,
with its maven project, is attached at the end of this article. After downloading the war file, host it in the
Tomcat server. Then we will be able to access it via http://10.100.0.65:8080/playground2.
[1]
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 the API element to achieve what we discussed in Steps
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. The complete maven project is attached at the end of the article. This handler
reads the OAuth2TokenValidationService URL of WSO2 IS and admin credentials to access that service,
from axis.xml of ESB. Then it calls this admin service and will pass the scope of the authorization with the
Access Token. Then WSO2 IS will verify them and inform the ESB back about the verification status.
package org.wso2.handler;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;
import org.apache.axis2.transport.http.HTTPConstants;
import org.apache.axis2.transport.http.HttpTransportProperties;
import org.apache.http.HttpHeaders;
import org.apache.synapse.core.axis2.Axis2MessageContext;
import org.wso2.carbon.identity.oauth2.stub.OAuth2TokenValidationServiceStub;
import org.wso2.carbon.identity.oauth2.stub.dto.OAuth2TokenValidationRequestDTO;
import org.apache.synapse.ManagedLifecycle;
import org.apache.synapse.MessageContext;
import org.apache.synapse.core.SynapseEnvironment;
import org.apache.synapse.rest.AbstractHandler;
import org.wso2.carbon.identity.oauth2.stub.dto.OAuth2TokenValidationRequestDTO_OAuth2AccessToken;
import java.rmi.RemoteException;
import java.util.Map;
public class SimpleOauthHandler extends AbstractHandler implements ManagedLifecycle {
private static final String securityHeader = HttpHeaders.AUTHORIZATION;
private static final String consumerKeyHeaderSegment = "Bearer";
private static final String oauthHeaderSplitter = ",";
private static final String consumerKeySegmentDelimiter = " ";
private static final String oauth2TokenValidationService = "oauth2TokenValidationService";
private static final String identityServerUserName = "identityServerUserName";
private static final String identityServerPw = "identityServerPw";
private static final String BEARER_TOKEN_TYPE = "bearer";
@Override
public boolean handleRequest(MessageContext messageContext) {
try {
ConfigurationContext configCtx = ConfigurationContextFactory.createConfigurationContextFromFileSystem(null, null);
//Read parameters from axis2.xml
String identityServerUrl = messageContext.getConfiguration().getAxisConfiguration().getParameter(oauth2TokenValidationService).getValue().toString();
String username = messageContext.getConfiguration().getAxisConfiguration().getParameter(identityServerUserName).getValue().toString();
String password = messageContext.getConfiguration().getAxisConfiguration().getParameter(identityServerPw).getValue().toString();
OAuth2TokenValidationServiceStub stub = new OAuth2TokenValidationServiceStub(configCtx, identityServerUrl);
ServiceClient client = stub._getServiceClient();
Options options = client.getOptions();
HttpTransportProperties.Authenticator authenticator = new HttpTransportProperties.Authenticator();
authenticator.setUsername(username);
authenticator.setPassword(password);
authenticator.setPreemptiveAuthentication(true);
options.setProperty(HTTPConstants.AUTHENTICATE, authenticator);
client.setOptions(options);
Map headers = (Map) ((Axis2MessageContext) messageContext).getAxis2MessageContext().
getProperty(org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS);
String apiKey = null;
if (headers != null) {
apiKey = extractCustomerKeyFromAuthHeader(headers);
}
OAuth2TokenValidationRequestDTO oauthReq = new OAuth2TokenValidationRequestDTO();
OAuth2TokenValidationRequestDTO_OAuth2AccessToken accessToken =
new org.wso2.carbon.identity.oauth2.stub.dto.OAuth2TokenValidationRequestDTO_OAuth2AccessToken();
accessToken.setTokenType(BEARER_TOKEN_TYPE);
accessToken.setIdentifier(apiKey);
oauthReq.setAccessToken(accessToken);
try {
return stub.validate(oauthReq).getValid();
} catch (RemoteException e) {
throw new Exception("Error while validating OAuth2 request", e);
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public String extractCustomerKeyFromAuthHeader(Map headersMap) {
String authHeader = (String) headersMap.get(securityHeader);
if (authHeader == null) {
return null;
}
if (authHeader.startsWith("OAuth ") || authHeader.startsWith("oauth ")) {
authHeader = authHeader.substring(authHeader.indexOf("o"));
}
String[] headers = authHeader.split(oauthHeaderSplitter);
if (headers != null) {
for (int i = 0; i < headers.length; i++) {
String[] elements = headers[i].split(consumerKeySegmentDelimiter);
if (elements != null && elements.length > 1) {
int j = 0;
boolean isConsumerKeyHeaderAvailable = false;
for (String element : elements) {
if (!"".equals(element.trim())) {
if (consumerKeyHeaderSegment.equals(elements[j].trim())) {
isConsumerKeyHeaderAvailable = true;
} else if (isConsumerKeyHeaderAvailable) {
return removeLeadingAndTrailing(elements[j].trim());
}
}
j++;
}
}
}
}
return null;
}
private String removeLeadingAndTrailing(String base) {
String result = base;
if (base.startsWith("\"") || base.endsWith("\"")) {
result = base.replace("\"", "");
}
return result.trim();
}
@Override
public boolean handleResponse(MessageContext messageContext) {
return true;
}
@Override
public void init(SynapseEnvironment synapseEnvironment) {
//ignore
}
@Override
public void destroy() {
//ignore
}
}
Then build the handler project ($ mvn clean install) and get the handler.jar created. Thereafter, put it in
$ESB_HOME/repository/components/lib.
Add the following configs to $ESB_HOME/repository/conf/axis2/axis2.xml.
https://10.100.0.65:9443/services/OAuth2TokenValidationServiceadminadmin
Restart ESB and go to Manage > Service Bus > Source View
Add the following API element config.
<header name="Authorization" scope="transport" action="remove"/>
<address uri="https://gdata.youtube.com/feeds/api/videos?q=wso2"/>
<handler class="org.wso2.handler.SimpleOauthHandler"/>
In this API element, we configure backend REST service, which needs to be secured with OAuth and the
handler class we have implemented. In this example, we have to remove the ?Authorization? header of the
incoming message, which is used to authenticate the service exposed by ESB from message before
sending it out to the backend service (unless YouTube tries to validate this token and gives an error
message saying ?Invalid Token?).
Now let?s configure WSO2 IS.
First, let?s register this Consumer App in WSO2 IS. Download and start WSO2 IS. Once 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 to the application. The callback URL of
our application is http://localhost:8080/playground2/oauth2client.
[2]
There are multiple grant types
supported by WSO2 IS. We will be discussing them individually, later in this article.
Once the app is added, it will be listed as follows.
Now Click on the application name and the following page will come up.
When the app has been 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 that
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
[3]
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 the following page to the user.
Once we click Continue, it will ask to authenticate the user (Step 2).
Once logged in, it will ask you to review and authorize the Consumer App?s authorization request. Then
we approve the request (Step 3).
Once we approved the request, the Consumer App get?s the authorization code (Step 4).
Now the 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 the Consumer App can send the request to ESB
with the 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
?
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 (Steps 8 and 9). Then the ESB will call backend REST service and get response back to the
Consumer App (Steps 10, 11 and 12).
Grant types supported by WSO2 IS
Authorization code
This is the type we discussed throughout the article, where IDP issues an Authorization code once the
Consumer App?s authorization request is approved by the user.
Implicit
In this type, the client secret is not involved. This is mostly used for mobile apps and web browser-based
apps (javascript apps, etc.) where the client secret cannot be kept in secret. In this method, once the user
authorizes the Consumer App?s authorization request, the app gets the Access Token directly.
Password
In this type, the user?s credentials are sent with initial request. This seems to contradict with the purpose
of having OAuth, which is avoiding giving away your password to a third-party application. But actually, it
doesn?t, because this method is supposed to be used by the applications that are owned by the resource
server itself, and not any other third party.
Client credentials
Resource owner (i.e. user) is not involved in this method. Here, the Consumer App uses its Client ID and
Client Secret to get an Access Token. This method is supposed to be used when the app needs to access
its own data rather than the user?s protected data.
Refresh token
In this method, IDP provides a Refresh Token (with Access Token), which the Consumer App can use to
get a new Access Token once the current Access Token is expired. So the user does not have to get
involved 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 the user to authenticate again. This is somewhat similar to the Refresh Token type.
Conclusion
You may want to allow third-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 third-party apps is not a solution, because it allows those apps to do
anything that user can do, regardless of what the user really wants the app to do on their behalf. In such a
situation, OAuth is a good solution that does not compromise the user account?s security, because in
OAuth the user does not have to divulge credentials to third-party apps. To secure your web service with
OAuth, you don?t have to implement it yourself from the scratch. WSO2 IS is an identity provider that does
just that for you with a few simple steps. Once you have configured your web service with WSO2 ESB,
third-party applications only have to register themselves in WSO2 IS, and you are ready to market.
Resources
Playground2.war
[4]
/ Source
[5]
Handler-1.0.0.jar
[6]
/ Source
[7]
References
[1] http://oauth.net/about/
[8]
[2] http://oauth.net/2/
[9]
[3] http://docs.wso2.org/display/ESB481/Securing+REST+APIs
[10]
[4] http://docs.wso2.org/display/ESB481/Getting+Started+with+REST+APIs#GettingStartedwithRESTAPIs-
addAPIs
[11]
[5] http://docs.wso2.org/display/IS460/OAuth+2.0+Playground+with+WSO2+Identity+Server
[12]
[6] http://malalanayake.wordpress.com/2013/04/05/apply-oauth2-0-base-security-for-rest-endpoint-with-
wso2esb-4-6-0-and-wso2is-4-1-1-alpha/
[13]
[7] http://aaronparecki.com/articles/2012/07/29/1/oauth2-simplified
[14]
[8] http://developer.yahoo.com/oauth/guide/oauth-whyoauth.html
[15]
Articles Identity and Entitlement Management Intermediate SOA Architecture
2013 WSO2 Inc.
footer
div#iFooter { background-color: #414042; font-family: Arial; } div#iFooter div.cFooterMenu { width: 980px;
margin: auto; color: #ffffff; padding: 25px 0px 10px; } div#iFooter div.cFooterMenu ul { list-style: none;
margin: 0px; padding: 0px; } div#iFooter div.cFooterMenu ul li { border: 0px; } div#iFooter div.cFooterMenu
ul li.cTitle { font-size: 14px; line-height: 14px; font-weight: bold; color: #ffffff; float: left; position: relative;
padding: 10px 10px 10px; width: auto; } div#iFooter div.cFooterMenu ul li.cTitle span { border-bottom: solid
1px #666666; display: block; width: 100%; padding: 0px 0px 10px; color: #ffffff; } div#iFooter
div.cFooterMenu ul li a { font-family: Arial; color: #ffffff; text-decoration: none; font-size: 12px; line-height:
12px; } div#iFooter div.cFooterMenu ul li a:hover { color: #f47b20; } div#iFooter div.cFooterMenu ul li ul li {
font-size: 12px; font-weight: normal; line-height: 12px; padding: 4px 0px; float: none; position: inherit; }
div#iFooter div.cFooterMenu ul li ul { margin: 5px 0px 0px; } div#iFooter div.cFooterMenu ul li ul li.cSubTitle
{ font-weight: bold; color: #cccccc; padding: 10px 0px 5px; border-bottom: dotted 1px #777777; margin:
0px 0px 5px; } div#iFooter div.cFooterLogo { height: 60px; background-color: #000000; } div#iFooter
div.cFooterLogo .cContent { width: 980px; height: 60px; margin: auto; text-align: right; background-image:
none; } div#iFooter div.cFooterLogo .cContent a img { float: left; margin: 17px 20px 0px 0px; } div#iFooter
div.cFooterLogo .cContent a { line-height: 60px; color: #ffffff; text-decoration: none; font-size: 12px; }
div#iFooter div.cFooterLogo .cContent a:hover { color: #f47b20; } div#iFooter div.cCopyRight { width:
980px; height: 30px; margin: auto; font-size: 12px; color: #cccccc; line-height: 60px; } div#iFooter
div.cFooterLogo span { float: right; line-height: 60px; color: #cccccc; } div#iFooter div.cFooterLogo ul { list-
style: none; margin: 0px; padding: 0px; } div#iFooter div.cFooterLogo ul li { float: left; position: relative;
padding: 0px 10px; border: 0px; line-height: 60px; } div#iFooter div.cFooterLogo ul li a { color: #cccccc; text-
decoration: none; line-height: 60px; } div#iFooter div.cFooterLogo ul li a:hover { color: #f47b20; } div.cClear
{ clear: both; } @media screen and (max-width: 900px) { div#iFooter div.cFooterLogo .cContent { width:
100%; } div#iFooter div.cFooterLogo span { width: 100%; margin: auto; text-align: center; height: 20px; }
div#iFooter div.cFooterMenu { display: none; } }
WSO2 Advantage
The Connected Business
API-centric SOA
Integrated Complete Platform
Open Source
Revolutionary Middleware
End to End Governance
Products
Middleware Platform
Overview
API Manager
Application Server
Business Activity Monitor
Business Process Server
Business Rules Server
Carbon
Cloud Gateway
Complex Event Processor
Data Services Server
Elastic Load Balancer
Enterprise Service Bus
Enterprise Store
Governance Registry
Identity Server
Message Broker
Storage Server
User Engagement Server
Development Tools
WSO2 Developer Studio
Mobile Platform
WSO2 Enterprise Mobility Manager
Cloud
Cloud Overview
WSO2 Private PaaS
WSO2 App Factory
WSO2 Public Cloud
App Cloud
Integration Cloud
API Cloud
Use Cases
Technology Challenges
IT Challenges
Business Challenges
Resources
Events Calender
WSO2 Library
White Papers
Case Studies
Analyst Reports
Presentations
On-demand Webinars
Videos
Product Documentation
Research
Partners
Support
Enterprise Support
Production Support
Development Support
Professional Services
Getting Started
Evaluation Support
QuickStart
Training and Certification
Community Support
StackOverFlow
Product Documentation
Knowledge Base Library
Support System Login
Subscribe to the Newsletter
Legal
Privacy
Report a problem with this page
2014 WSO2
var rw_ext_id=''; var pkBaseURL = (("https:" == document.location.protocol)
?"https://connect.wso2.com/wso2/" : "http://connect.wso2.com/wso2/");
document.write(unescape("%3Cscript src='" + pkBaseURL +"std/resource/script/rwts.js'
type='text/javascript'%3E%3C/script%3E")); rw_log(pkBaseURL, 4220);
Source URL: http://wso2.com/library/articles/2014/02/securing-your-web-service-with-oauth2-using-wso2-identity-server-
1
Links:
[1]
http://www.google.com/url?q=http://10.100.0.65:8080/playground2&sa=D&sntz=1&usg=AFQjCNFV6rPuWH2mIjehD7Acl8c7gQFuuA
[2]
http://www.google.com/url?q=http://localhost:8080/playground2/oauth2client&sa=D&sntz=1&usg=AFQjCNEd_dFI2BS2p1mrORi19VQFUnx6dw
[3] http://l10.100.0.65:8080/playground2
[4]
https://www.google.com/url?q=https://dl.dropboxusercontent.com/u/69447299/OAuth_Article_Resources/playground2.war&sa=D&sntz=1&usg=AFQjCNGyNbGA0uBZIoV184YG_3LYQQCeLA
[5]
https://www.google.com/url?q=https://dl.dropboxusercontent.com/u/69447299/OAuth_Article_Resources/playground2_src.zip&sa=D&sntz=1&usg=AFQjCNHIB-
CmQrF5tiHMfwmXZ3VoMG-qQw
[6] https://www.google.com/url?q=https://dl.dropboxusercontent.com/u/69447299/OAuth_Article_Resources/handler-
1.1.0.jar&sa=D&sntz=1&usg=AFQjCNH8chXQb-kLP7qZBXn28HMHPUwU-w
[7]
https://www.google.com/url?q=https://dl.dropboxusercontent.com/u/69447299/OAuth_Article_Resources/handler_src.zip&sa=D&sntz=1&usg=AFQjCNH2aOy7UU0DwxYgniF7mKaKajBz6w
[8] http://oauth.net/about/
[9] http://oauth.net/2/
[10] http://docs.wso2.org/display/ESB481/Securing REST APIs
[11] http://docs.wso2.org/display/ESB481/Getting Started with REST APIs#GettingStartedwithRESTAPIs-addAPIs
[12] http://docs.wso2.org/display/IS460/OAuth 2.0 Playground with WSO2 Identity Server
[13] http://malalanayake.wordpress.com/2013/04/05/apply-oauth2-0-base-security-for-rest-endpoint-with-wso2esb-4-6-0-
and-wso2is-4-1-1-alpha/
[14] http://aaronparecki.com/articles/2012/07/29/1/oauth2-simplified
[15] http://developer.yahoo.com/oauth/guide/oauth-whyoauth.html

You might also like