OAuth2Helper.java 13.7 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  javax.jcr.AccessDeniedException
 *  javax.jcr.Credentials
 *  javax.jcr.Node
 *  javax.jcr.RepositoryException
 *  javax.jcr.Session
 *  javax.jcr.SimpleCredentials
 *  javax.jcr.UnsupportedRepositoryOperationException
 *  javax.jcr.Value
 *  javax.jcr.ValueFormatException
 *  javax.jcr.nodetype.NodeType
 *  javax.jcr.security.AccessControlManager
 *  javax.jcr.security.Privilege
 *  javax.servlet.http.HttpServletResponse
 *  org.apache.commons.lang.StringUtils
 *  org.apache.jackrabbit.api.JackrabbitSession
 *  org.apache.jackrabbit.api.security.user.Authorizable
 *  org.apache.jackrabbit.api.security.user.User
 *  org.apache.jackrabbit.api.security.user.UserManager
 *  org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils
 *  org.apache.oltu.oauth2.common.exception.OAuthProblemException
 *  org.apache.oltu.oauth2.common.exception.OAuthSystemException
 *  org.apache.oltu.oauth2.jwt.ClaimsSet
 *  org.apache.oltu.oauth2.jwt.JWT
 *  org.apache.oltu.oauth2.jwt.io.JWTReader
 *  org.apache.sling.jcr.api.SlingRepository
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.adobe.granite.oauth.server.impl.helper;

import com.adobe.granite.oauth.server.OAuth2ResourceServer;
import com.adobe.granite.oauth.server.Scope;
import java.io.IOException;
import java.security.Principal;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.jcr.AccessDeniedException;
import javax.jcr.Credentials;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
import javax.jcr.nodetype.NodeType;
import javax.jcr.security.AccessControlManager;
import javax.jcr.security.Privilege;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.apache.jackrabbit.api.JackrabbitSession;
import org.apache.jackrabbit.api.security.user.Authorizable;
import org.apache.jackrabbit.api.security.user.User;
import org.apache.jackrabbit.api.security.user.UserManager;
import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.jwt.ClaimsSet;
import org.apache.oltu.oauth2.jwt.JWT;
import org.apache.oltu.oauth2.jwt.io.JWTReader;
import org.apache.sling.jcr.api.SlingRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/*
 * This class specifies class file version 49.0 but uses Java 6 signatures.  Assumed Java 6.
 */
public class OAuth2Helper {
    private static final Logger logger = LoggerFactory.getLogger(OAuth2Helper.class);

    public static Authorizable getOAuthClientAuthorizable(Session session, String clientId) throws RepositoryException, OAuthSystemException {
        UserManager um = ((JackrabbitSession)session).getUserManager();
        Iterator iterator = um.findAuthorizables("oauth:clientId", clientId);
        if (iterator.hasNext()) {
            Authorizable user = (Authorizable)iterator.next();
            if (iterator.hasNext()) {
                logger.error("getOAuthClientAuthorizable: not allowed, more than one client exist with clientId {}", (Object)clientId);
                throw new OAuthSystemException(" failed to retreive the client");
            }
            if (!(user instanceof User)) {
                logger.error("getOAuthClientAuthorizable: invalid/forged clientId {}", (Object)clientId);
                throw new OAuthSystemException("failed to retreive the client");
            }
            if (!user.hasProperty("oauth/" + clientId + "/" + "oauth:clientId")) {
                logger.error("getOAuthClientAuthorizable: invalid/forged clientId {}", (Object)clientId);
                throw new OAuthSystemException("failed to retreive the client");
            }
            if (!"oauth:client".equals(session.getNode(user.getPath() + "/oauth/" + clientId).getPrimaryNodeType().getName())) {
                logger.error("getOAuthClientAuthorizable: invalid/forged clientId {}", (Object)clientId);
                throw new OAuthSystemException("failed to retreive the client");
            }
            return user;
        }
        logger.info("clientId {} not found", (Object)clientId);
        return null;
    }

    public static String getOAuthClientPropertyValue(Authorizable user, String clientId, String propertyName) throws ValueFormatException, IllegalStateException, RepositoryException {
        propertyName = "oauth/" + clientId + "/" + propertyName;
        if (user.hasProperty(propertyName)) {
            Value[] value = user.getProperty(propertyName);
            if (value != null && value[0] != null) {
                return value[0].getString();
            }
            logger.info("property {} not found", (Object)propertyName);
            return null;
        }
        logger.info("property {} not found", (Object)propertyName);
        return null;
    }

    public static void handleOAuthSystemException(OAuthSystemException e, HttpServletResponse response) throws IOException {
        logger.error("OAuth System Exception ", (Throwable)e);
        response.sendError(500);
    }

    public static String getScopes(Set<String> scopes) {
        return StringUtils.join(scopes, (char)',');
    }

    public static Set<String> getScopesSet(String scopes) {
        HashSet<String> scopesSet = new HashSet<String>();
        if (scopes != null && scopes.length() > 0) {
            for (String s : scopes.split(",")) {
                scopesSet.add(s);
            }
        }
        return scopesSet;
    }

    public static Set<String> getAllowedDefaultScopesSet(String scopes) {
        HashSet<String> scopesSet = new HashSet<String>();
        if (scopes != null && scopes.length() > 0) {
            for (String s : scopes.split(",")) {
                if (s.startsWith("/")) continue;
                scopesSet.add(s);
            }
        }
        return scopesSet;
    }

    public static Set<String> getDefaultScopesResourcePathSet(OAuth2ResourceServer oAuth2ResourceServer, String scopes, User user) {
        Set<String> scopesSet = OAuth2Helper.getAllowedDefaultScopesSet(scopes);
        HashSet<String> paths = new HashSet<String>();
        Map<String, Scope> scopesMap = oAuth2ResourceServer.getAllowedScopes();
        for (String scope : scopesSet) {
            String resourcePath;
            if (!scopesMap.containsKey(scope) || (resourcePath = scopesMap.get(scope).getResourcePath(user)) == null) continue;
            paths.add(resourcePath);
        }
        return paths;
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    public static boolean checkPrivileges(SlingRepository repository, Session session, User user, Set<String> scopes) throws UnsupportedRepositoryOperationException, RepositoryException {
        boolean validScope;
        Session userSession = null;
        validScope = true;
        try {
            if (scopes == null || scopes.isEmpty()) {
                boolean bl = true;
                return bl;
            }
            userSession = repository.impersonateFromService("oauthservice", (Credentials)new SimpleCredentials(user.getID(), new char[0]), null);
            for (String path : scopes) {
                if (userSession.hasPermission(path, "read")) continue;
                logger.debug("the user {} doesn't have enough privilege for path {}", (Object)user.getID(), (Object)path);
                validScope = false;
                break;
            }
        }
        finally {
            if (userSession != null && userSession.isLive()) {
                userSession.logout();
            }
        }
        return validScope;
    }

    public static User createUser(Session session, final String userId, String intermediatePath) throws AccessDeniedException, UnsupportedRepositoryOperationException, RepositoryException {
        User user = null;
        UserManager um = ((JackrabbitSession)session).getUserManager();
        Principal principal = new Principal(){

            public String getName() {
                return userId;
            }
        };
        user = um.createUser(userId, null, principal, intermediatePath);
        if (!um.isAutoSave()) {
            session.save();
        }
        return user;
    }

    public static void deleteUser(Session session, String userId) throws AccessDeniedException, UnsupportedRepositoryOperationException, RepositoryException {
        UserManager um = ((JackrabbitSession)session).getUserManager();
        Authorizable authorizable = um.getAuthorizable(userId);
        if (authorizable instanceof User) {
            User user = (User)um.getAuthorizable(userId);
            user.remove();
            if (!um.isAutoSave()) {
                session.save();
            }
        }
    }

    public static void addACLEntries(Session session, Principal principal, Set<String> paths, boolean allow) throws RepositoryException {
        AccessControlManager acm = session.getAccessControlManager();
        Privilege[] privilegesArray = new Privilege[]{acm.privilegeFromName("{http://www.jcp.org/jcr/1.0}read")};
        for (String path : paths) {
            AccessControlUtils.addAccessControlEntry((Session)session, (String)path, (Principal)principal, (Privilege[])privilegesArray, (boolean)allow);
        }
        if (session.hasPendingChanges()) {
            session.save();
        }
    }

    public static User getUser(Session session, String userId) throws RepositoryException {
        UserManager um;
        Authorizable auth;
        if (userId != null && (auth = (um = ((JackrabbitSession)session).getUserManager()).getAuthorizable(userId)) != null && auth instanceof User) {
            logger.debug("found user with userid {}", (Object)userId);
            return (User)auth;
        }
        return null;
    }

    public static String getSubject(String accessToken) {
        JWT jwt = (JWT)new JWTReader().read(accessToken);
        return jwt.getClaimsSet().getSubject();
    }

    public static String getContentType(String token) {
        JWT jwt = (JWT)new JWTReader().read(token);
        return (String)jwt.getClaimsSet().getCustomField("cty", String.class);
    }

    public static String getScopes(String accessToken) {
        JWT jwt = (JWT)new JWTReader().read(accessToken);
        return (String)jwt.getClaimsSet().getCustomField("scope", String.class);
    }

    public static String getJwtUserId(String accessToken) {
        return "oauth-" + new StringBuilder(accessToken).reverse().toString();
    }

    public static String getJwtFromUserId(String userId) {
        return new StringBuilder(userId.substring("oauth-".length())).reverse().toString();
    }

    public static void validateAuthorizationEndpointInput(Session session, String clientId, String redirectUri) throws OAuthProblemException, OAuthSystemException {
        try {
            Authorizable user = OAuth2Helper.getOAuthClientAuthorizable(session, clientId);
            if (user == null) {
                logger.debug("validateRedirectURI: Invalid value {} for parameter client_id", (Object)clientId);
                OAuthProblemException oAuthProblemException = OAuthProblemException.error((String)"invalid_client", (String)"Invalid client");
                oAuthProblemException.responseStatus(400);
                throw oAuthProblemException;
            }
            String redirectUriStored = OAuth2Helper.getOAuthClientPropertyValue(user, clientId, "oauth:redirectURI");
            if (!redirectUriStored.equalsIgnoreCase(redirectUri)) {
                logger.debug("validateRedirectURI: The redirect URI in the request {} did not match a registered redirect URI {}", (Object)redirectUri, (Object)redirectUriStored);
                OAuthProblemException oAuthProblemException = OAuthProblemException.error((String)"redirect_uri_mismatch", (String)("The redirect URI in the request " + redirectUri + " did not match a registered redirect URI"));
                oAuthProblemException.responseStatus(400);
                throw oAuthProblemException;
            }
        }
        catch (RepositoryException e) {
            logger.error("validateRedirectURI: failed while accessing repository", (Throwable)e);
            throw new OAuthSystemException("failed while accessing repository");
        }
    }

    public static void validateScopes(OAuth2ResourceServer oAuth2ResourceServer, Set<String> scopes, boolean serviceAccount) throws OAuthProblemException, OAuthSystemException {
        boolean invalidScope = false;
        Map<String, Scope> allowedScopes = oAuth2ResourceServer.getAllowedScopes();
        if (!allowedScopes.keySet().containsAll(scopes)) {
            logger.debug("the provided scope is not whitelisted");
            invalidScope = true;
        }
        if (!serviceAccount) {
            for (String scope : scopes) {
                if (!OAuth2Helper.isReplicationScope(allowedScopes.get(scope))) continue;
                invalidScope = true;
            }
        }
        if (invalidScope) {
            logger.info("the provided scope is not valid");
            OAuthProblemException oAuthProblemException = OAuthProblemException.error((String)"invalid_scope", (String)"Invalid scope");
            oAuthProblemException.responseStatus(400);
            throw oAuthProblemException;
        }
    }

    public static boolean isReplicationScope(Scope scope) {
        if (scope == null) {
            return false;
        }
        if ("replicate".equals(scope.getName())) {
            return true;
        }
        return false;
    }

}