/* * Copyright (c) 2005-2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.wso2.carbon.identity.oauth.mediator; import java.lang.String; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import org.apache.axis2.AxisFault; import org.apache.axis2.context.ConfigurationContext; import org.apache.axis2.context.ConfigurationContextFactory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.synapse.MessageContext; import org.apache.synapse.SynapseException; import org.apache.synapse.core.SynapseEnvironment; import org.apache.synapse.core.axis2.Axis2MessageContext; import org.apache.synapse.mediators.AbstractMediator; import org.apache.synapse.transport.nhttp.NhttpConstants; import org.wso2.carbon.identity.oauth.stub.dto.OAuthConsumerDTO; import org.wso2.carbon.identity.oauth.stub.types.Parameters; import org.wso2.carbon.identity.oauth2.stub.dto.OAuth2TokenValidationRequestDTO_TokenValidationContextParam; import org.wso2.carbon.identity.oauth2.stub.dto.OAuth2TokenValidationResponseDTO; public class OAuthMediator extends AbstractMediator { private static final Log log = LogFactory.getLog(OAuthMediator.class); private String remoteServiceUrl; private String username; private String password; ConfigurationContext cfgCtx = null; private String clientRepository = null; private String axis2xml = null; public final static String DEFAULT_CLIENT_REPO = "./samples/axis2Client/client_repo"; public final static String DEFAULT_AXIS2_XML = "./samples/axis2Client/client_repo/conf/axis2.xml"; /** * {@inheritDoc} */ public void init(SynapseEnvironment synEnv) { try { cfgCtx = ConfigurationContextFactory.createConfigurationContextFromFileSystem(clientRepository != null ? clientRepository : DEFAULT_CLIENT_REPO, axis2xml != null ? axis2xml : DEFAULT_AXIS2_XML); } catch (AxisFault e) { String msg = "Error initializing OAuth mediator : " + e.getMessage(); log.error(msg, e); throw new SynapseException(msg, e); } } /** * {@inheritDoc} */ @Override public boolean mediate(MessageContext synCtx) { if (synCtx.getEnvironment().isDebuggerEnabled()) { if (super.divertMediationRoute(synCtx)) { return true; } } // checks if the message carries OAuth params boolean isOauth2 = validateRequest(synCtx); if (isOauth2) { return handleOAuth2(synCtx); } else { return handleOAuth1a(synCtx); } } /** * Checks if the message contains Authorization header or query strings * * @param synCtx * @return */ private boolean validateRequest(MessageContext synCtx) { boolean isOauth2 = false; String accessToken = null; org.apache.axis2.context.MessageContext msgContext = ((Axis2MessageContext) synCtx).getAxis2MessageContext(); Map headersMap = (Map) msgContext.getProperty(org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS); String authHeader = (String) headersMap.get("Authorization"); // if we can't find the OAuth header, prompt error if (authHeader == null) { throw new SynapseException("Not a valid OAuth Request"); } // checking for OAuth 2.0 params if (authHeader != null && authHeader.startsWith(OAuthConstants.BEARER)) { isOauth2 = true; accessToken = authHeader.substring(7).trim(); } // not a valid OAuth 2.0 request if (isOauth2 == true && accessToken == null) { throw new SynapseException("OAuth 2.0 access_token could not found in the request"); } return isOauth2; } /** * Try to authenticate using OAuth 2.0 * * @param synCtx * @return true/false */ private boolean handleOAuth2(MessageContext synCtx) { log.debug("Validating the OAuth 2.0 Request"); OAuth2TokenValidationResponseDTO respDTO; Map headersMap; try { OAuth2TokenValidationServiceClient oauth2Client = new OAuth2TokenValidationServiceClient( getRemoteServiceUrl(), getUsername(), getPassword(), cfgCtx); org.apache.axis2.context.MessageContext msgContext = ((Axis2MessageContext) synCtx).getAxis2MessageContext(); headersMap = (Map) msgContext.getProperty(org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS); String authHeader = (String) headersMap.get("Authorization"); String accessToken = authHeader.substring(7).trim(); List<OAuth2TokenValidationRequestDTO_TokenValidationContextParam> contextParams = new ArrayList<OAuth2TokenValidationRequestDTO_TokenValidationContextParam>(); for(int i = 0; ;i++){ if(synCtx.getProperty("oauth_context_param_key_" + i) != null && synCtx.getProperty("oauth_context_param_key_" + i) instanceof String && !synCtx.getProperty("oauth_context_param_key_" + i).equals("") && synCtx.getProperty("oauth_context_param_value_" + i) != null && synCtx.getProperty("oauth_context_param_value_" + i) instanceof String && !synCtx.getProperty("oauth_context_param_value_" + i).equals("")){ String paramKey = (String)synCtx.getProperty("oauth_context_param_key_" + i); String paramValue = (String)synCtx.getProperty("oauth_context_param_value_" + i); OAuth2TokenValidationRequestDTO_TokenValidationContextParam param = new OAuth2TokenValidationRequestDTO_TokenValidationContextParam(); param.setKey(paramKey); param.setValue(paramValue); contextParams.add(param); } else { break; } } respDTO = oauth2Client.validateAuthenticationRequest(accessToken ,contextParams); } catch (Exception e) { log.error("Error occured while validating oauth access token", e); throw new SynapseException("Error occured while validating oauth 2.0 access token"); } if(!respDTO.getValid()){ throw new SynapseException("OAuth 2.0 authentication failed"); } if(respDTO.getAuthorizationContextToken() != null){ headersMap.put("X-JWT-Assertion", respDTO.getAuthorizationContextToken().getTokenString()); } // Scope validation. if(synCtx.getProperty(OAuthConstants.OAUTH2_SCOPE_VALIDATION_ENABLED) != null && Boolean.parseBoolean((String)synCtx.getProperty(OAuthConstants.OAUTH2_SCOPE_VALIDATION_ENABLED))){ String[] scopes = respDTO.getScope(); if(scopes != null) { String apiScope = (String) synCtx.getProperty(OAuthConstants.SCOPE); // if API, default value if(apiScope == null) { apiScope = (String) synCtx.getProperty("SYNAPSE_REST_API"); } // if proxy service, default value. if(apiScope == null){ apiScope = ((Axis2MessageContext) synCtx).getAxis2MessageContext().getAxisService().getName(); } List<String> values = new ArrayList<String>(Arrays.asList(scopes)); if(!values.contains(apiScope)){ log.debug("Valid Scope is not match for given access token. OAuth2 scope validation is failed."); throw new SynapseException("OAuth 2.0 authentication failed"); } } else { log.debug("Scope is null for given access token. OAuth2 scope validation is failed."); throw new SynapseException("OAuth 2.0 authentication failed"); } } return true; } /** * Try to authenticate using OAuth 1.0a. * * @param synCtx * @return */ private boolean handleOAuth1a(MessageContext synCtx) { log.debug("Validating the OAuth 1.0a Request"); OAuthServiceClient client = null; ConfigurationContext configContext = null; OAuthConsumerDTO consumer = null; boolean isValidConsumer = false; try { Parameters params = populateOauthConsumerData(synCtx); client = new OAuthServiceClient(getRemoteServiceUrl(), configContext); if (params != null && params.getOauthToken() == null) { consumer = new OAuthConsumerDTO(); consumer.setBaseString(params.getBaseString()); consumer.setHttpMethod(params.getHttpMethod()); consumer.setOauthConsumerKey(params.getOauthConsumerKey()); consumer.setOauthNonce(params.getOauthNonce()); consumer.setOauthSignature(params.getOauthSignature()); consumer.setOauthSignatureMethod(params.getOauthSignatureMethod()); consumer.setOauthTimeStamp(params.getOauthTimeStamp()); isValidConsumer = client.isOAuthConsumerValid(consumer); } else { isValidConsumer = client.validateAuthenticationRequest(params); } if (!isValidConsumer) { throw new SynapseException("OAuth authentication failed"); } else { return true; } } catch (Exception e) { log.error("Error occured while validating oauth consumer", e); throw new SynapseException("Error occured while validating oauth consumer"); } } /** * Populates the Parameters object from the OAuth authorization header or * query string. * * @param synCtx * @return */ private Parameters populateOauthConsumerData(MessageContext synCtx) { org.apache.axis2.context.MessageContext msgContext = ((Axis2MessageContext) synCtx).getAxis2MessageContext(); Map headersMap = (Map) msgContext.getProperty(org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS); String authHeader = (String) headersMap.get("Authorization"); String queryString = (String) msgContext.getProperty(NhttpConstants.REST_URL_POSTFIX); Parameters params = null; String splitChar = ","; boolean noAuthorizationHeader = false; params = new Parameters(); String operation = null; if (queryString.indexOf("?") > -1) { String temp = queryString; queryString = queryString.substring(queryString.indexOf("?") + 1); operation = temp.substring(0, temp.indexOf("?") + 1); } if (authHeader == null) { noAuthorizationHeader = true; // No Authorization header available. authHeader = queryString; splitChar = "&"; } StringBuffer nonAuthParams = new StringBuffer(); if (authHeader != null) { if (authHeader.startsWith("OAuth ")) { authHeader = authHeader.substring(authHeader.indexOf("o")); } String[] headers = authHeader.split(splitChar); if (headers != null && headers.length > 0) { for (String header : headers) { String[] elements = header.split("="); if (elements != null && elements.length > 0) { if (OAuthConstants.OAUTH_CONSUMER_KEY.equals(elements[0].trim())) { params.setOauthConsumerKey(removeLeadingAndTrailingQuatation(elements[1].trim())); } else if (OAuthConstants.OAUTH_NONCE.equals(elements[0].trim())) { params.setOauthNonce(removeLeadingAndTrailingQuatation(elements[1].trim())); } else if (OAuthConstants.OAUTH_SIGNATURE.equals(elements[0].trim())) { params.setOauthSignature(removeLeadingAndTrailingQuatation(elements[1].trim())); } else if (OAuthConstants.OAUTH_SIGNATURE_METHOD.equals(elements[0].trim())) { params.setOauthSignatureMethod(removeLeadingAndTrailingQuatation(elements[1].trim())); } else if (OAuthConstants.OAUTH_TIMESTAMP.equals(elements[0].trim())) { params.setOauthTimeStamp(removeLeadingAndTrailingQuatation(elements[1].trim())); } else if (OAuthConstants.OAUTH_CALLBACK.equals(elements[0].trim())) { params.setOauthCallback(removeLeadingAndTrailingQuatation(elements[1].trim())); } else if (OAuthConstants.SCOPE.equals(elements[0].trim())) { params.setScope(removeLeadingAndTrailingQuatation(elements[1].trim())); } else if (OAuthConstants.OAUTH_DISPLAY_NAME.equals(elements[0].trim())) { params.setDisplayName(removeLeadingAndTrailingQuatation(elements[1].trim())); } else if (OAuthConstants.OAUTH_TOKEN.equals(elements[0].trim())) { params.setOauthToken(removeLeadingAndTrailingQuatation(elements[1].trim())); } else if (OAuthConstants.OAUTH_VERIFIER.equals(elements[0].trim())) { params.setOauthTokenVerifier(removeLeadingAndTrailingQuatation(elements[1].trim())); } else if (OAuthConstants.OAUTH_TOKEN_SECRET.equals(elements[0].trim())) { params.setOauthTokenSecret(removeLeadingAndTrailingQuatation(elements[1].trim())); } else if (OAuthConstants.OAUTH_VERSION.equals(elements[0].trim())) { params.setVersion(removeLeadingAndTrailingQuatation(elements[1].trim())); } else { nonAuthParams.append(elements[0].trim() + "=" + removeLeadingAndTrailingQuatation(elements[1].trim()) + "&"); } } } } } String nonOauthParamStr = nonAuthParams.toString(); if (!noAuthorizationHeader) { nonOauthParamStr = queryString + "&"; } String scope = (String)synCtx.getProperty(OAuthConstants.SCOPE); if (scope == null) { throw new SynapseException("Unable to find SCOPE value in Synapse Message Context"); } params.setScope(scope); params.setHttpMethod((String) msgContext.getProperty("HTTP_METHOD")); String prefix = (String) msgContext.getProperty(NhttpConstants.SERVICE_PREFIX); if (nonOauthParamStr.length() > 1) { params.setBaseString(prefix + operation + nonOauthParamStr.substring(0, nonOauthParamStr.length() - 1)); } else { params.setBaseString(prefix); } return params; } private String removeLeadingAndTrailingQuatation(String base) { String result = base; if (base.startsWith("\"") || base.endsWith("\"")) { result = base.replace("\"", ""); } return result.trim(); } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getRemoteServiceUrl() { if (remoteServiceUrl != null) { if (!remoteServiceUrl.endsWith("/")) { remoteServiceUrl += "/"; } } return remoteServiceUrl; } public void setRemoteServiceUrl(String remoteServiceUrl) { this.remoteServiceUrl = remoteServiceUrl; } @Override public boolean isContentAware() { return false; } }