/** * Copyright 2005-2014 Restlet * * The contents of this file are subject to the terms of one of the following * open source licenses: Apache 2.0 or or EPL 1.0 (the "Licenses"). You can * select the license that you prefer but you may not use this file except in * compliance with one of these Licenses. * * You can obtain a copy of the Apache 2.0 license at * http://www.opensource.org/licenses/apache-2.0 * * You can obtain a copy of the EPL 1.0 license at * http://www.opensource.org/licenses/eclipse-1.0 * * See the Licenses for the specific language governing permissions and * limitations under the Licenses. * * Alternatively, you can obtain a royalty free commercial license with less * limitations, transferable or non-transferable, directly at * http://restlet.com/products/restlet-framework * * Restlet is a registered trademark of Restlet S.A.S. */ package org.restlet.ext.oauth; import java.util.logging.Level; import java.util.logging.Logger; import org.json.JSONException; import org.json.JSONObject; import org.restlet.Request; import org.restlet.Response; import org.restlet.data.CacheDirective; import org.restlet.data.ChallengeResponse; import org.restlet.data.ChallengeScheme; import org.restlet.data.ClientInfo; import org.restlet.data.Form; import org.restlet.data.MediaType; import org.restlet.data.Method; import org.restlet.data.Reference; import org.restlet.ext.json.JsonRepresentation; import org.restlet.ext.oauth.internal.Scopes; import org.restlet.representation.Representation; import org.restlet.resource.ClientResource; import org.restlet.security.User; import org.restlet.security.Verifier; /** * Verifier for OAuth 2.0 Protected Resources. Typically use with * ChallengeAuthenticator. "Bearer" and "MAC" challenge schemes are may * supported. * * @author Shotaro Uchida <fantom@xmaker.mx> * @see <a href="http://tools.ietf.org/html/draft-ietf-oauth-v2-bearer-22"> * Bearer Token Usage</a> * @see <a href="http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01"> * MAC Access Authentication</a> */ public class TokenVerifier implements Verifier { // public static final ChallengeScheme HTTP_BEARER = // new ChallengeScheme("HTTP_BEARER", "Bearer", // "The OAuth 2.0 Authorization Framework: Bearer Token Usage"); // public static final ChallengeScheme HTTP_MAC = // new ChallengeScheme("HTTP_MAC", "MAC", "MAC Access Authentication"); private static final Logger logger = Logger.getLogger(TokenVerifier.class .getName()); private static JSONObject createBearerAuthRequest(String token) throws JSONException { JSONObject request = new JSONObject(); request.put(OAuthServerResource.TOKEN_TYPE, OAuthServerResource.TOKEN_TYPE_BEARER); request.put(OAuthServerResource.ACCESS_TOKEN, token); return request; } private boolean acceptBodyMethod = false; // 2.2. Form-Encoded Body // Parameter private boolean acceptQueryMethod = false; // 2.3. URI Query Parameter private Reference authReference; public TokenVerifier(Reference authReference) { this.authReference = authReference; } private String getAccessTokenFromBody(Request request) { Method method = request.getMethod(); if (method.equals(Method.GET)) { return null; } Representation entity = request.getEntity(); if (entity != null && !MediaType.APPLICATION_WWW_FORM .equals(entity.getMediaType())) { return null; } Form form = new Form(request.getEntity()); final String token = form .getFirstValue(OAuthServerResource.ACCESS_TOKEN); if (token == null || token.isEmpty()) { return null; } // Restore the body request.setEntity(form.getWebRepresentation()); logger.fine("Found Bearer Token in Body."); return token; } private String getAccessTokenFromQuery(Request request) { // Try to find token in URI query Form params = request.getOriginalRef().getQueryAsForm(); String token = params.getFirstValue(OAuthServerResource.ACCESS_TOKEN); if (token != null && !token.isEmpty()) { logger.fine("Found Bearer Token in URI query."); return token; } return null; } /** * @return the acceptBodyMethod */ public boolean isAcceptBodyMethod() { return acceptBodyMethod; } /** * @return the acceptQueryMethod */ public boolean isAcceptQueryMethod() { return acceptQueryMethod; } /** * @param acceptBodyMethod * the acceptBodyMethod to set */ public void setAcceptBodyMethod(boolean acceptBodyMethod) { this.acceptBodyMethod = acceptBodyMethod; } /** * @param acceptQueryMethod * the acceptQueryMethod to set */ public void setAcceptQueryMethod(boolean acceptQueryMethod) { this.acceptQueryMethod = acceptQueryMethod; } public int verify(Request request, Response response) { final JSONObject authRequest; try { ChallengeResponse cr = request.getChallengeResponse(); if (cr == null) { // Try Bearer alternative methods String bearer = null; if (acceptBodyMethod) { bearer = getAccessTokenFromBody(request); } if (bearer == null && acceptQueryMethod) { bearer = getAccessTokenFromQuery(request); if (bearer != null) { OAuthServerResource.addCacheDirective(response, CacheDirective.privateInfo()); } } if (bearer == null) { return RESULT_MISSING; } logger.config("Verify: Bearer (Alternative)"); authRequest = createBearerAuthRequest(bearer); } else if (ChallengeScheme.HTTP_OAUTH_BEARER.equals(cr.getScheme())) { logger.config("Verify: Bearer"); final String bearer = cr.getRawValue(); if (bearer == null || bearer.isEmpty()) { return RESULT_MISSING; } authRequest = createBearerAuthRequest(bearer); }/* * else if (cr.getScheme().equals(HTTP_MAC)) { // TODO } */else { return RESULT_UNSUPPORTED; } } catch (Exception ex) { return RESULT_INVALID; } ClientResource authResource = new ClientResource(authReference); JsonRepresentation jsonRepresentation; JSONObject jsonResponse; try { logger.fine("Post auth request to auth resource..."); Representation resp = authResource.post(new JsonRepresentation( authRequest)); jsonRepresentation = new JsonRepresentation(resp); jsonResponse = jsonRepresentation.getJsonObject(); } catch (Exception ex) { logger.log(Level.SEVERE, null, ex); return RESULT_INVALID; } if (jsonResponse.has(OAuthServerResource.ERROR)) { try { String error = jsonResponse .getString(OAuthServerResource.ERROR); logger.warning(error); logger.warning(jsonResponse .getString(OAuthServerResource.ERROR_DESC)); } catch (JSONException ex) { logger.log(Level.SEVERE, null, ex); } // TODO: Configure challenge request return RESULT_INVALID; } try { ClientInfo clientInfo = request.getClientInfo(); clientInfo.setUser(new User(jsonResponse .getString(OAuthServerResource.USERNAME))); clientInfo.setRoles(Scopes.toRoles(jsonResponse .getString(OAuthServerResource.SCOPE))); } catch (JSONException ex) { return RESULT_INVALID; } return RESULT_VALID; } }