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

org.glassfish.jersey.server.oauth1.DefaultOAuth1Provider Maven / Gradle / Ivy

/*
 * Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package org.glassfish.jersey.server.oauth1;

import java.security.Principal;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.Provider;

import org.glassfish.jersey.internal.util.collection.ImmutableMultivaluedMap;

/** Default in-memory implementation of OAuth1Provider. Stores consumers and tokens
 * in static hash maps. Provides some additional helper methods for consumer
 * and token management (registering new consumers, retrieving a list of all
 * registered consumers per owner, listing the authorized tokens per principal,
 * revoking tokens, etc.)
 *
 * @author Martin Matula
 * @author Miroslav Fuksa
 */
@Provider
public class DefaultOAuth1Provider implements OAuth1Provider {

    private static final ConcurrentHashMap consumerByConsumerKey = new ConcurrentHashMap<>();
    private static final ConcurrentHashMap accessTokenByTokenString = new ConcurrentHashMap<>();
    private static final ConcurrentHashMap requestTokenByTokenString = new ConcurrentHashMap<>();
    private static final ConcurrentHashMap verifierByTokenString = new ConcurrentHashMap<>();

    @Override
    public Consumer getConsumer(final String consumerKey) {
        return consumerByConsumerKey.get(consumerKey);
    }

    /**
     * Register a new consumer.
     *
     * @param owner Identifier of the owner that registers the consumer (user ID or similar).
     * @param attributes Additional attributes (name-values pairs - to store additional
     * information about the consumer, such as name, URI, description, etc.)
     * @return {@link Consumer} object for the newly registered consumer.
     */
    public Consumer registerConsumer(final String owner, final MultivaluedMap attributes) {
        return registerConsumer(owner, newUUIDString(), newUUIDString(), attributes);
    }

    /**
     * Register a new consumer configured with Consumer Key.
     *
     * @param owner Identifier of the owner that registers the consumer (user ID or similar).
     * @param key Consumer key.
     * @param secret Consumer key secret.
     * @param attributes Additional attributes (name-values pairs - to store additional
     * information about the consumer, such as name, URI, description, etc.)
     * @return {@link Consumer} object for the newly registered consumer.
     */
    public Consumer registerConsumer(final String owner,
                                     final String key,
                                     final String secret,
                                     final MultivaluedMap attributes) {
        final Consumer c = new Consumer(key, secret, owner, attributes);
        consumerByConsumerKey.put(c.getKey(), c);
        return c;
    }

    /** Returns a set of consumers registered by a given owner.
     *
     * @param owner Identifier of the owner that registered the consumers to be retrieved.
     * @return consumers registered by the owner.
     */
    public Set getConsumers(final String owner) {
        final Set result = new HashSet<>();
        for (final Consumer consumer : consumerByConsumerKey.values()) {
            if (consumer.getOwner().equals(owner)) {
                result.add(consumer);
            }
        }
        return result;
    }

    /** Returns a list of access tokens authorized with the supplied principal name.
     *
     * @param principalName Principal name for which to retrieve the authorized tokens.
     * @return authorized access tokens.
     */
    public Set getAccessTokens(final String principalName) {
        final Set tokens = new HashSet<>();
        for (final Token token : accessTokenByTokenString.values()) {
            if (principalName.equals(token.getPrincipal().getName())) {
                tokens.add(token);
            }
        }
        return tokens;
    }

    /** Authorizes a request token for given principal and roles and returns
     * verifier.
     *
     * @param token Request token to authorize.
     * @param userPrincipal User principal to authorize the token for.
     * @param roles Set of roles to authorize the token for.
     * @return OAuth verifier value for exchanging this token for an access token.
     */
    public String authorizeToken(final Token token, final Principal userPrincipal, final Set roles) {
        final Token authorized = token.authorize(userPrincipal, roles);
        requestTokenByTokenString.put(token.getToken(), authorized);
        final String verifier = newUUIDString();
        verifierByTokenString.put(token.getToken(), verifier);
        return verifier;
    }

    /** Checks if the supplied token is authorized for a given principal name
     * and if so, revokes the authorization.
     *
     * @param token Access token to revoke the authorization for.
     * @param principalName Principal name the token is currently authorized for.
     */
    public void revokeAccessToken(final String token, final String principalName) {
        final Token t = (Token) getAccessToken(token);
        if (t != null && t.getPrincipal().getName().equals(principalName)) {
            accessTokenByTokenString.remove(token);
        }
    }

    /** Generates a new non-guessable random string (used for token/customer
     * strings, secrets and verifier.
     *
     * @return Random UUID string.
     */
    protected String newUUIDString() {
        final String tmp = UUID.randomUUID().toString();
        return tmp.replaceAll("-", "");
    }

    @Override
    public Token getRequestToken(final String token) {
        return requestTokenByTokenString.get(token);
    }

    @Override
    public OAuth1Token newRequestToken(final String consumerKey,
                                       final String callbackUrl,
                                       final Map> attributes) {
        final Token rt = new Token(newUUIDString(), newUUIDString(), consumerKey, callbackUrl, attributes);
        requestTokenByTokenString.put(rt.getToken(), rt);
        return rt;
    }

    @Override
    public OAuth1Token newAccessToken(final OAuth1Token requestToken, final String verifier) {
        if (verifier == null || requestToken == null || !verifier.equals(verifierByTokenString.remove(requestToken.getToken()))) {
            return null;
        }
        final Token token = requestTokenByTokenString.remove(requestToken.getToken());
        if (token == null) {
            return null;
        }
        final Token at = new Token(newUUIDString(), newUUIDString(), token);
        accessTokenByTokenString.put(at.getToken(), at);
        return at;
    }

    public void addAccessToken(final String token,
                               final String secret,
                               final String consumerKey,
                               final String callbackUrl,
                               final Principal principal,
                               final Set roles,
                               final MultivaluedMap attributes) {
        final Token accessToken = new Token(token, secret, consumerKey, callbackUrl, principal, roles, attributes);

        accessTokenByTokenString.put(accessToken.getToken(), accessToken);
    }

    @Override
    public OAuth1Token getAccessToken(final String token) {
        return accessTokenByTokenString.get(token);
    }

    /** Simple read-only implementation of {@link OAuth1Consumer}.
     */
    public static class Consumer implements OAuth1Consumer {

        private final String key;
        private final String secret;
        private final String owner;
        private final MultivaluedMap attributes;

        private Consumer(final String key, final String secret, final String owner, final Map> attributes) {
            this.key = key;
            this.secret = secret;
            this.owner = owner;
            this.attributes = getImmutableMap(attributes);
        }

        @Override
        public String getKey() {
            return key;
        }

        @Override
        public String getSecret() {
            return secret;
        }

        /** Returns identifier of owner of this consumer - i.e. who registered
         * the consumer.
         *
         * @return consumer owner
         */
        public String getOwner() {
            return owner;
        }

        /** Returns additional attributes associated with the consumer (e.g. name,
         * URI, description, etc.)
         *
         * @return name-values pairs of additional attributes
         */
        public MultivaluedMap getAttributes() {
            return attributes;
        }

        @Override
        public Principal getPrincipal() {
            return null;
        }

        @Override
        public boolean isInRole(final String role) {
            return false;
        }
    }

    private static MultivaluedMap getImmutableMap(final Map> map) {
        final MultivaluedHashMap newMap = new MultivaluedHashMap<>();
        for (final Map.Entry> entry : map.entrySet()) {
            newMap.put(entry.getKey(), entry.getValue());
        }
        return newMap;
    }

    /** Simple immutable implementation of {@link OAuth1Token}.
     *
     */
    public class Token implements OAuth1Token {

        private final String token;
        private final String secret;
        private final String consumerKey;
        private final String callbackUrl;
        private final Principal principal;
        private final Set roles;
        private final MultivaluedMap attribs;

        protected Token(final String token, final String secret, final String consumerKey, final String callbackUrl,
                        final Principal principal, final Set roles, final MultivaluedMap attributes) {
            this.token = token;
            this.secret = secret;
            this.consumerKey = consumerKey;
            this.callbackUrl = callbackUrl;
            this.principal = principal;
            this.roles = roles;
            this.attribs = attributes;
        }

        public Token(final String token,
                     final String secret,
                     final String consumerKey,
                     final String callbackUrl,
                     final Map> attributes) {
            this(token, secret, consumerKey, callbackUrl, null, Collections.emptySet(),
                    new ImmutableMultivaluedMap<>(getImmutableMap(attributes)));
        }

        public Token(final String token, final String secret, final Token requestToken) {
            this(token, secret, requestToken.getConsumer().getKey(), null,
                    requestToken.principal, requestToken.roles, ImmutableMultivaluedMap.empty());
        }

        @Override
        public String getToken() {
            return token;
        }

        @Override
        public String getSecret() {
            return secret;
        }

        @Override
        public OAuth1Consumer getConsumer() {
            return DefaultOAuth1Provider.this.getConsumer(consumerKey);
        }

        @Override
        public MultivaluedMap getAttributes() {
            return attribs;
        }

        @Override
        public Principal getPrincipal() {
            return principal;
        }

        @Override
        public boolean isInRole(final String role) {
            return roles.contains(role);
        }

        /** Returns callback URL for this token (applicable just to request tokens)
         *
         * @return callback url
         */
        public String getCallbackUrl() {
            return callbackUrl;
        }

        /** Authorizes this token - i.e. generates a clone with principal and roles set
         * to the passed values.
         *
         * @param principal Principal to add to the token.
         * @param roles Roles to add to the token.
         * @return Cloned token with the principal and roles set.
         */
        protected Token authorize(final Principal principal, final Set roles) {
            return new Token(token, secret, consumerKey, callbackUrl, principal,
                    roles == null ? Collections.emptySet() : new HashSet<>(roles), attribs);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy