All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.krotscheck.kangaroo.authz.oauth2.resource.authorize.AuthCodeHandler Maven / Gradle / Ivy

There is a newer version: 1.4.0
Show newest version
/*
 * Copyright (c) 2017 Michael Krotscheck
 *
 * Licensed 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 net.krotscheck.kangaroo.authz.oauth2.resource.authorize;

import net.krotscheck.kangaroo.authz.common.authenticator.IAuthenticator;
import net.krotscheck.kangaroo.authz.common.database.entity.ApplicationScope;
import net.krotscheck.kangaroo.authz.common.database.entity.Authenticator;
import net.krotscheck.kangaroo.authz.common.database.entity.AuthenticatorState;
import net.krotscheck.kangaroo.authz.common.database.entity.ClientType;
import net.krotscheck.kangaroo.authz.common.database.entity.OAuthToken;
import net.krotscheck.kangaroo.authz.common.database.entity.OAuthTokenType;
import net.krotscheck.kangaroo.authz.common.database.entity.UserIdentity;
import net.krotscheck.kangaroo.authz.common.util.ValidationUtil;
import net.krotscheck.kangaroo.common.hibernate.id.IdUtil;
import org.apache.commons.lang3.StringUtils;
import org.glassfish.jersey.internal.inject.AbstractBinder;
import org.glassfish.jersey.internal.inject.InjectionManager;
import org.glassfish.jersey.process.internal.RequestScoped;
import org.hibernate.Session;

import javax.inject.Inject;
import javax.servlet.http.HttpSession;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import java.net.URI;
import java.util.SortedMap;

/**
 * This handler is passed all authorization code requests.
 *
 * @author Michael Krotscheck
 */
public final class AuthCodeHandler implements IAuthorizeHandler {

    /**
     * The injection manager.
     */
    private final InjectionManager injector;

    /**
     * The active database session.
     */
    private final Session session;

    /**
     * Current request URI.
     */
    private final UriInfo uriInfo;

    /**
     * Create a new handler.
     *
     * @param injector The injection manager.
     * @param session  The hibernate session.
     * @param uriInfo  The URI info for the current request.
     */
    @Inject
    @SuppressWarnings({"CPD-START"})
    public AuthCodeHandler(final InjectionManager injector,
                           final Session session,
                           @Context final UriInfo uriInfo) {
        this.injector = injector;
        this.session = session;
        this.uriInfo = uriInfo;
    }

    /**
     * Provided a stored intermediate authenticator state, attempt to resolve
     * an instance of the associated authenticator implementation.
     *
     * @param state The state to resolve.
     * @return An authenticator Impl, available from the injection context.
     */
    public IAuthenticator getAuthenticator(final AuthenticatorState state) {
        Authenticator a = state.getAuthenticator();
        return injector.getInstance(IAuthenticator.class, a.getType().name());
    }

    /**
     * Handle an authorization request using the Auth Code flow.
     *
     * @param browserSession The browser session, maintained via cookies.
     * @param auth           The authenticator to use to process this
     *                       request.
     * @param redirect       The redirect (already validated) to which
     *                       the response  should be returned.
     * @param scopes         The (validated) list of scopes requested by
     *                       the user.
     * @param state          The client's requested state ID.
     * @return The response from the handler.
     */
    @Override
    public Response handle(final HttpSession browserSession,
                           final Authenticator auth,
                           final URI redirect,
                           final SortedMap scopes,
                           final String state) {

        // Retrieve the authenticator instance.
        IAuthenticator authImpl = injector.getInstance(
                IAuthenticator.class, auth.getType().name());

        // Create the intermediate authorization store.
        AuthenticatorState callbackState = new AuthenticatorState();
        callbackState.setClientState(state);
        callbackState.setClientScopes(scopes);
        callbackState.setClientRedirect(redirect);
        callbackState.setAuthenticator(auth);

        // Save the state.
        session.save(callbackState);

        // Generate the redirection url.
        URI callback = buildCallback(uriInfo, callbackState);

        // Run the authenticator.
        return authImpl.delegate(auth, callback);
    }

    /**
     * Handle a callback response from the IdP (Authenticator). Provided with
     * the previously stored state, this method should return to the client
     * either a valid token, or an appropriate error response.
     *
     * @param s              The request state previously saved by the client.
     * @param browserSession The browser session, maintained via cookies.
     * @return A response entity indicating success or failure.
     */
    @Override
    public Response callback(final AuthenticatorState s,
                             final HttpSession browserSession) {

        URI callback = buildCallback(uriInfo, s);

        IAuthenticator a = getAuthenticator(s);
        UserIdentity i = a.authenticate(s.getAuthenticator(),
                uriInfo.getQueryParameters(), callback);

        // Build the token.
        OAuthToken t = new OAuthToken();
        t.setClient(s.getAuthenticator().getClient());
        t.setIdentity(i);
        t.setScopes(ValidationUtil
                .validateScope(s.getClientScopes(), i.getUser().getRole()));
        t.setTokenType(OAuthTokenType.Authorization);
        t.setExpiresIn(s.getAuthenticator().getClient()
                .getAuthorizationCodeExpiresIn());
        t.setRedirect(s.getClientRedirect());
        t.setIdentity(i);
        t.setIssuer(uriInfo.getAbsolutePath().getHost());

        // Persist and get an ID.
        session.save(t);
        session.delete(s);

        // Build our redirect URL.
        UriBuilder responseBuilder = UriBuilder.fromUri(s.getClientRedirect());
        responseBuilder.queryParam("code", IdUtil.toString(t.getId()));
        if (!StringUtils.isEmpty(s.getClientState())) {
            responseBuilder.queryParam("state", s.getClientState());
        }

        return Response.status(Status.FOUND)
                .location(responseBuilder.build())
                .build();
    }

    /**
     * HK2 Binder for our injector context.
     */
    @SuppressWarnings({"CPD-END"})
    public static final class Binder extends AbstractBinder {

        @Override
        protected void configure() {
            bind(AuthCodeHandler.class)
                    .to(IAuthorizeHandler.class)
                    .named(ClientType.AuthorizationGrant.name())
                    .in(RequestScoped.class);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy