Package org.restlet.ext.oauth

Source Code of org.restlet.ext.oauth.OAuthAuthorizer

/**
* Copyright 2005-2011 Noelios Technologies.
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: LGPL 3.0 or LGPL 2.1 or CDDL 1.0 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 LGPL 3.0 license at
* http://www.opensource.org/licenses/lgpl-3.0.html
*
* You can obtain a copy of the LGPL 2.1 license at
* http://www.opensource.org/licenses/lgpl-2.1.php
*
* You can obtain a copy of the CDDL 1.0 license at
* http://www.opensource.org/licenses/cddl1.php
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* 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://www.noelios.com/products/restlet-engine
*
* Restlet is a registered trademark of Noelios Technologies.
*/

package org.restlet.ext.oauth;

import java.io.IOException;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.data.ChallengeRequest;
import org.restlet.data.ChallengeScheme;
import org.restlet.data.Form;
import org.restlet.data.MediaType;
import org.restlet.data.Method;
import org.restlet.data.Parameter;
import org.restlet.data.Reference;
import org.restlet.data.Status;
import org.restlet.ext.json.JsonRepresentation;
import org.restlet.ext.oauth.internal.CookieCopyClientResource;
import org.restlet.ext.oauth.internal.JsonStringRepresentation;
import org.restlet.ext.oauth.internal.Scopes;
import org.restlet.representation.Representation;
import org.restlet.resource.ClientResource;
import org.restlet.security.Role;
import org.restlet.security.RoleAuthorizer;
import org.restlet.security.User;
import org.restlet.util.Series;

/**
* Class for OAuth 2.0 protection of REST resources. Can be deployed outside the
* Authorization Server Restlet application. A Validation resource must be
* started and mapped in the auth server.
*
* Example invocation:
*
* <pre>
* {@code
* public Restlet createInboundRoot(){
*   ...
*   OAuthAuthorizer auth = new OAuthAuthorizer(
*              "http://localhost:8080/OAuth2Provider/validate",
*              "http://localhost:8080/OAuth2Provider/authorize");
*   auth.setNext(ProtectedResource.class);
*   router.attach("/me", auth);
*   ...
* }
* }
* @see org.restlet.ext.oauth.ValidationServerResource
*
* @author Kristoffer Gronowski
*/
public class OAuthAuthorizer extends RoleAuthorizer {

    // Resource authenticateURI;
    protected final Reference authorizeRef;

    protected final Reference validateRef;

    /**
     * Default constructor.
     */
    protected OAuthAuthorizer() {
        this.authorizeRef = null;
        this.validateRef = null;
    } // For extending the class

    /**
     * Constructor.
     *
     * @param validationRef
     *            The validation URI referencing the auth server validation
     *            resource.
     */
    public OAuthAuthorizer(Reference validationRef) {
        this(validationRef, null); // Nothing on errors
    }

    /**
     * Sets up a RemoteAuthorizer.
     *
     * @param validationRef
     *            The validation URI referencing the auth server validation
     *            resource.
     * @param authorizationRef
     *            The authorization URI referencing that should be invoked on
     *            errors.
     */
    public OAuthAuthorizer(Reference validationRef, Reference authorizationRef) {
        authorizeRef = authorizationRef;
        validateRef = validationRef;
    }

    /**
     * Constructor.
     *
     * @param validationRef
     *            The validation URI referencing the auth server validation
     *            resource.
     * @param authorizationRef
     *            The authorization URI referencing that should be invoked on
     *            errors.
     */
    public OAuthAuthorizer(String validationRef, String authorizationRef) {
        this(validationRef, authorizationRef, false);
    }

    /**
     * Sets up a Remote or Local Authorizer. Can only be deployed together with
     * the Authorization Server Restlet application. A Validation resource must
     * be started and mapped in the auth server.
     *
     *
     * @param validationRef
     *            The validation URI referencing the auth server validation
     *            resource.
     * @param authorizationRef
     *            The authorization URI referencing that should be invoked on
     *            errors.
     * @param local
     *            if true a local authorizer will be created
     */
    public OAuthAuthorizer(String validationRef, String authorizationRef,
            boolean local) {
        if (local) {
            authorizeRef = new Reference(authorizationRef);
            validateRef = new Reference("riap://application" + validationRef);
        } else {
            authorizeRef = new Reference(authorizationRef);
            validateRef = new Reference(validationRef);
        }
    }

    @Override
    public boolean authorize(Request req, Response resp) {
        getLogger().info("Checking for param access_token");
        String accessToken = getAccessToken(req);

        if (accessToken == null || accessToken.length() == 0) {
            ChallengeRequest cr = new ChallengeRequest(
                    ChallengeScheme.HTTP_OAUTH, "oauth"); // TODO set realm
            Series<Parameter> parameters = new Form();
            parameters.add("error", OAuthError.INVALID_REQUEST.name());
            cr.setParameters(parameters);
            resp.getChallengeRequests().add(cr);
            resp.setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
        } else {
            getLogger().info("Found Access Token " + accessToken);
            ClientResource authResource = new CookieCopyClientResource(
                    validateRef);

            JSONObject request;
            try {
                request = createValidationRequest(accessToken, req);
                // Representation repr = this.createJsonRepresentation(request);
                Representation repr = new JsonStringRepresentation(request);
                getLogger().info("Posting to validator... json = " + request);
                // RETRIEVE JSON...WORKAROUND TO HANDLE ANDROID
                Representation r = authResource.post(repr);
                getLogger().info("After posting to validator...");
                repr.release();
                getLogger().info(
                        "Got Respose from auth resource OK "
                                + r.getClass().getCanonicalName());
                JsonRepresentation returned = new JsonRepresentation(r);

                // GET OBJECT
                JSONObject response = returned.getJsonObject();
                boolean authenticated = response.getBoolean("authenticated");

                if (response.has("tokenOwner"))
                    this.setUser(req, response, accessToken);

                String error = null;
                if (response.has("error"))
                    error = response.getString("error");

                getLogger().info("In Auth Filer -> " + authenticated);

                // Clean-up
                returned.release();
                r.release();
                authResource.release();

                if (authenticated)
                    return true;

                // handle any errors:
                handleError(error, resp);

            } catch (JSONException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                if (authResource != null) {
                    authResource.getResponse().release();
                    authResource.release();
                }
            }
        }

        return false;

    }

    // GET SIZE TO HANDLE BUG IN GLASSFISH
    /*
     * private Representation createJsonRepresentation(JSONObject request){
     * JsonRepresentation repr = new JsonRepresentation(request);
     * StringRepresentation sr = new StringRepresentation( request.toString());
     * sr.setCharacterSet(repr.getCharacterSet()); repr.setSize(sr.getSize());
     * sr.release(); return repr; }
     */

    /**
     * Returns an instance of {@link JSONObject} that represents the validation
     * request.
     *
     * @param accessToken
     *            The access token.
     * @param req
     *            The current request.
     * @return An instance of {@link JSONObject} that represents the validation
     *         request.
     * @throws JSONException
     */
    private JSONObject createValidationRequest(String accessToken, Request req)
            throws JSONException {
        JSONObject request = new JSONObject();
        Reference uri = req.getOriginalRef();

        request.put("access_token", accessToken);

        // add any roles...
        List<Role> roles = this.getAuthorizedRoles();
        if (roles != null && roles.size() > 0) {
            JSONArray jArray = new JSONArray();
            for (Role r : roles)
                jArray.put(Scopes.toScope(r));
            request.put("scope", jArray);
            getLogger().info("Found scopes: " + jArray.toString());
        }
        String owner = (String) req.getAttributes().get("oauth-user");
        if (owner != null && owner.length() > 0) {
            getLogger().info("Found Owner:" + owner);
            request.put("owner", owner);
        }
        request.put("uri", uri.getHierarchicalPart());
        return request;
    }

    /**
     * Returns the access token taken from a given request.
     *
     * @param request
     *            The request.
     * @return The access token taken from a given request.
     */
    private String getAccessToken(Request request) {
        // Auth Header present
        String accessToken = null;
        if (request.getChallengeResponse() != null) {
            accessToken = request.getChallengeResponse().getRawValue();
            getLogger().info("Found Authorization header" + accessToken);
        }
        // Check query for token
        else if (accessToken == null || accessToken.length() == 0) {
            getLogger().info(
                    "Didn't contain a Authorization header - checking query");
            accessToken = request.getOriginalRef().getQueryAsForm()
                    .getFirstValue(OAuthServerResource.OAUTH_TOKEN);

            // check body if all else fail:
            if (accessToken == null || accessToken.length() == 0) {
                if (request.getMethod() == Method.POST
                        || request.getMethod() == Method.PUT
                        || request.getMethod() == Method.DELETE) {
                    Representation r = request.getEntity();
                    if (r != null
                            && MediaType.APPLICATION_WWW_FORM.equals(r
                                    .getMediaType())) {
                        // Search for an OAuth Token
                        Form form = new Form(r);
                        accessToken = form
                                .getFirstValue(OAuthServerResource.OAUTH_TOKEN);
                        if (accessToken != null && accessToken.length() > 0) {
                            // restore the entity body
                            request.setEntity(form.getWebRepresentation());
                        }
                    }
                }
            }
        }
        return accessToken;
    }

    /**
     * Completes the given {@link Response} according to the given error.
     *
     * @param error
     *            The error.
     * @param resp
     *            The response to complete.
     */
    private void handleError(String error, Response resp) {
        if (error != null && error.length() > 0) {
            ChallengeRequest cr = new ChallengeRequest(
                    ChallengeScheme.HTTP_OAUTH, "oauth"); // TODO set
            // realm
            Series<Parameter> parameters = new Form();
            parameters.add("error", error);
            OAuthError code = OAuthError.valueOf(error);

            switch (code) {
            case INVALID_REQUEST:
                // TODO report bug in Restlet and verify, can not handle
                // space char.
                // parameters.add("error_description",
                // "The request is missing a required parameter.");
                resp.setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
                break;
            case INVALID_TOKEN:
            case EXPIRED_TOKEN:
                // parameters.add("error_description",
                // "The access token provided is invalid.");
                resp.setStatus(Status.CLIENT_ERROR_UNAUTHORIZED);
                break;
            case INSUFFICIENT_SCOPE:
                // parameters.add("error_description",
                // "The request requires higher privileges than provided "
                // +"by the access token.");
                resp.setStatus(Status.CLIENT_ERROR_FORBIDDEN);
                break;

            }

            // parameters.add("error_uri",authorizeRef.toString());
            cr.setParameters(parameters);
            resp.getChallengeRequests().add(cr);
        }
    }

    /**
     * Instantiates the {@link User} according to the given credentials and
     * update the given {@link Request}.
     *
     * @param req
     *            The request.
     * @param response
     *            The {@link JSONObject} that represents the response.
     * @param accessToken
     *            The access token.
     * @throws JSONException
     */
    private void setUser(Request req, JSONObject response, String accessToken)
            throws JSONException {
        String tokenOwner = response.getString("tokenOwner");
        getLogger().info(
                "User " + tokenOwner + " is accessing : "
                        + req.getOriginalRef());
        User user = new User(tokenOwner, accessToken);

        // Set the user so that the Resource knows who is executing
        // Based on the person issuing the token in the first place.
        req.getClientInfo().setUser(user);
        req.getClientInfo().setAuthenticated(true);
    }

    @Override
    protected int unauthorized(Request request, Response response) {
        return STOP;
        // TODO propose to add if statement to Authenticator.
        // if( response.getStatus().isRedirection()) return STOP;
        // return super.unauthorized(request, response);
    }
}
TOP

Related Classes of org.restlet.ext.oauth.OAuthAuthorizer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.