OAuth2ServerAuthenticationHandler.java 12.2 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.adobe.granite.crypto.CryptoSupport
 *  com.adobe.granite.oauth.jwt.JwsValidator
 *  javax.jcr.PathNotFoundException
 *  javax.jcr.RepositoryException
 *  javax.jcr.Session
 *  javax.servlet.http.HttpServletRequest
 *  javax.servlet.http.HttpServletResponse
 *  org.apache.felix.scr.annotations.Activate
 *  org.apache.felix.scr.annotations.Component
 *  org.apache.felix.scr.annotations.ConfigurationPolicy
 *  org.apache.felix.scr.annotations.Deactivate
 *  org.apache.felix.scr.annotations.Properties
 *  org.apache.felix.scr.annotations.Property
 *  org.apache.felix.scr.annotations.Reference
 *  org.apache.felix.scr.annotations.Service
 *  org.apache.jackrabbit.api.security.user.User
 *  org.apache.oltu.oauth2.common.exception.OAuthProblemException
 *  org.apache.oltu.oauth2.common.exception.OAuthSystemException
 *  org.apache.oltu.oauth2.common.message.types.ParameterStyle
 *  org.apache.oltu.oauth2.rs.request.OAuthAccessResourceRequest
 *  org.apache.sling.auth.core.spi.AuthenticationHandler
 *  org.apache.sling.auth.core.spi.AuthenticationInfo
 *  org.apache.sling.commons.osgi.PropertiesUtil
 *  org.apache.sling.jcr.api.SlingRepository
 *  org.apache.sling.settings.SlingSettingsService
 *  org.osgi.framework.BundleContext
 *  org.osgi.service.component.ComponentContext
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.adobe.granite.oauth.server.auth.impl;

import com.adobe.granite.crypto.CryptoSupport;
import com.adobe.granite.oauth.jwt.JwsValidator;
import com.adobe.granite.oauth.server.OAuth2ResourceServer;
import com.adobe.granite.oauth.server.auth.impl.JaasHelper;
import com.adobe.granite.oauth.server.auth.impl.OAuth2ServerCredentials;
import com.adobe.granite.oauth.server.impl.helper.OAuth2Helper;
import java.io.IOException;
import java.security.Principal;
import java.util.Dictionary;
import java.util.Set;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.ConfigurationPolicy;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.jackrabbit.api.security.user.User;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.types.ParameterStyle;
import org.apache.oltu.oauth2.rs.request.OAuthAccessResourceRequest;
import org.apache.sling.auth.core.spi.AuthenticationHandler;
import org.apache.sling.auth.core.spi.AuthenticationInfo;
import org.apache.sling.commons.osgi.PropertiesUtil;
import org.apache.sling.jcr.api.SlingRepository;
import org.apache.sling.settings.SlingSettingsService;
import org.osgi.framework.BundleContext;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(metatype=1, policy=ConfigurationPolicy.REQUIRE, label="%oauth.server.name", description="%oauth.server.description")
@Service
@Properties(value={@Property(name="service.ranking", intValue={200000}), @Property(name="path", value={"/"}), @Property(name="jaas.controlFlag", value={"sufficient"}), @Property(name="jaas.realmName", value={"jackrabbit.oak"}), @Property(name="jaas.ranking", intValue={1000})})
public class OAuth2ServerAuthenticationHandler
implements AuthenticationHandler {
    private final Logger log;
    private static final String REPLICATION_RECEIVER = "replication-receiver";
    @Property(name="authtype", propertyPrivate=1)
    private static final String TYPE = "OAUTH2SERVER";
    private final JaasHelper jaasHelper;
    private static final String OFFLINE_VALIDATION = "oauth.offline.validation";
    @Property(name="oauth.offline.validation")
    private static final boolean OFFLINE_VALIDATION_DEFAULT = true;
    @Reference
    private SlingRepository repository;
    @Reference
    private SlingSettingsService settings;
    @Reference
    private CryptoSupport cryptoSupport;
    @Reference
    JwsValidator jwsValidator;
    @Reference
    private OAuth2ResourceServer oAuth2ResourceServer;
    private boolean offlineValidation;

    public OAuth2ServerAuthenticationHandler() {
        this.log = LoggerFactory.getLogger(this.getClass());
        this.jaasHelper = new JaasHelper();
    }

    @Activate
    private void activate(ComponentContext ctx) {
        Dictionary properties = ctx.getProperties();
        this.jaasHelper.open(ctx.getBundleContext(), properties);
        this.offlineValidation = PropertiesUtil.toBoolean(properties.get("oauth.offline.validation"), (boolean)true);
    }

    @Deactivate
    private void deactivate() {
        this.jaasHelper.close();
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    public AuthenticationInfo extractCredentials(HttpServletRequest request, HttpServletResponse response) {
        if (this.jaasHelper.enabled()) {
            block14 : {
                boolean validAccessToken;
                String accessToken = this.getAccessToken(request);
                this.log.debug("extractCredentials: extracted access token");
                if (accessToken != null && (validAccessToken = this.isValidAccessToken(accessToken))) {
                    String userId = OAuth2Helper.getSubject(accessToken);
                    this.log.debug("extractCredentials: extracted userId {}", (Object)userId);
                    if (userId != null) {
                        Session oauthServiceSession = null;
                        AuthenticationInfo authenticationInfo = null;
                        try {
                            String jwtUserId;
                            String oauthUserId;
                            oauthServiceSession = this.repository.loginService(null, null);
                            User user = OAuth2Helper.getUser(oauthServiceSession, userId);
                            if (user == null) break block14;
                            String scopes = OAuth2Helper.getScopes(accessToken);
                            this.log.debug("extractCredentials: extracted scopes {}", (Object)scopes);
                            Set<String> scopesSet = OAuth2Helper.getScopesSet(scopes);
                            if (scopesSet.contains("replicate")) {
                                oauthUserId = "replication-receiver";
                            } else {
                                jwtUserId = OAuth2Helper.getJwtUserId(accessToken);
                                User oauthUser = OAuth2Helper.getUser(oauthServiceSession, jwtUserId);
                                if (oauthUser == null) {
                                    this.log.debug("create oauth user and assign privileges");
                                    String intermediatePath = "oauth/" + jwtUserId.substring("oauth-".length(), 9);
                                    oauthUser = OAuth2Helper.createUser(oauthServiceSession, jwtUserId, intermediatePath);
                                    try {
                                        OAuth2Helper.addACLEntries(oauthServiceSession, oauthUser.getPrincipal(), OAuth2Helper.getDefaultScopesResourcePathSet(this.oAuth2ResourceServer, scopes, user), true);
                                    }
                                    catch (PathNotFoundException exception) {
                                        this.log.debug("default scopes ACE could not be applied");
                                    }
                                }
                                oauthUserId = oauthUser.getID();
                            }
                            this.log.debug("extractCredentials: creating authentication info with user {}", (Object)oauthUserId);
                            authenticationInfo = new AuthenticationInfo("OAUTH2SERVER", oauthUserId);
                            authenticationInfo.put("user.jcr.credentials", (Object)new OAuth2ServerCredentials(oauthUserId));
                            jwtUserId = authenticationInfo;
                            return jwtUserId;
                        }
                        catch (RepositoryException e) {
                            this.log.error("extractCredentials: Failed to impersonate user ", (Throwable)e);
                        }
                        finally {
                            if (oauthServiceSession != null) {
                                oauthServiceSession.logout();
                            }
                        }
                    }
                }
            }
            this.log.debug("extractCredentials: returning null");
            return null;
        }
        this.log.error("this feature is available only for Oak deployments");
        return null;
    }

    public boolean requestCredentials(HttpServletRequest request, HttpServletResponse response) throws IOException {
        return false;
    }

    public void dropCredentials(HttpServletRequest request, HttpServletResponse response) throws IOException {
    }

    private boolean isValidAccessToken(String accessToken) {
        boolean validAccessToken = false;
        try {
            if (this.offlineValidation) {
                String contentType;
                validAccessToken = this.jwsValidator.validate(accessToken);
                if (validAccessToken && !"at".equals(contentType = OAuth2Helper.getContentType(accessToken))) {
                    validAccessToken = false;
                }
            } else {
                this.log.info("isValidAccessToken: online validation is not supported for now");
            }
        }
        catch (Exception e) {
            this.log.debug("isValidAccessToken: error while validate the token ", (Throwable)e);
        }
        return validAccessToken;
    }

    private String getAccessToken(HttpServletRequest request) {
        String accessToken = null;
        try {
            OAuthAccessResourceRequest oauthRequest = new OAuthAccessResourceRequest(request, new ParameterStyle[]{ParameterStyle.HEADER});
            accessToken = oauthRequest.getAccessToken();
        }
        catch (OAuthSystemException e) {
            this.log.debug("getAccessToken: Wrong Authorization header format; ignoring");
        }
        catch (OAuthProblemException e) {
            this.log.debug("getAccessToken: Wrong Authorization header format; ignoring");
        }
        return accessToken;
    }

    protected void bindRepository(SlingRepository slingRepository) {
        this.repository = slingRepository;
    }

    protected void unbindRepository(SlingRepository slingRepository) {
        if (this.repository == slingRepository) {
            this.repository = null;
        }
    }

    protected void bindSettings(SlingSettingsService slingSettingsService) {
        this.settings = slingSettingsService;
    }

    protected void unbindSettings(SlingSettingsService slingSettingsService) {
        if (this.settings == slingSettingsService) {
            this.settings = null;
        }
    }

    protected void bindCryptoSupport(CryptoSupport cryptoSupport) {
        this.cryptoSupport = cryptoSupport;
    }

    protected void unbindCryptoSupport(CryptoSupport cryptoSupport) {
        if (this.cryptoSupport == cryptoSupport) {
            this.cryptoSupport = null;
        }
    }

    protected void bindJwsValidator(JwsValidator jwsValidator) {
        this.jwsValidator = jwsValidator;
    }

    protected void unbindJwsValidator(JwsValidator jwsValidator) {
        if (this.jwsValidator == jwsValidator) {
            this.jwsValidator = null;
        }
    }

    protected void bindOAuth2ResourceServer(OAuth2ResourceServer oAuth2ResourceServer) {
        this.oAuth2ResourceServer = oAuth2ResourceServer;
    }

    protected void unbindOAuth2ResourceServer(OAuth2ResourceServer oAuth2ResourceServer) {
        if (this.oAuth2ResourceServer == oAuth2ResourceServer) {
            this.oAuth2ResourceServer = null;
        }
    }
}