001/*
002 * (C) Copyright 2017-2018 Nuxeo (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Arnaud Kervern
018 *     Thomas Roger
019 *     Florent Guillaume
020 */
021package org.nuxeo.ecm.platform.oauth2;
022
023import static java.lang.Boolean.FALSE;
024import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION;
025import static org.nuxeo.ecm.platform.oauth2.Constants.TOKEN_SERVICE;
026
027import java.util.List;
028import java.util.Map;
029
030import javax.servlet.http.HttpServletRequest;
031import javax.servlet.http.HttpServletResponse;
032
033import org.apache.commons.lang3.StringUtils;
034import org.apache.commons.logging.Log;
035import org.apache.commons.logging.LogFactory;
036import org.nuxeo.ecm.platform.api.login.UserIdentificationInfo;
037import org.nuxeo.ecm.platform.oauth2.clients.OAuth2ClientService;
038import org.nuxeo.ecm.platform.oauth2.tokens.NuxeoOAuth2Token;
039import org.nuxeo.ecm.platform.oauth2.tokens.OAuth2TokenStore;
040import org.nuxeo.ecm.platform.ui.web.auth.interfaces.NuxeoAuthenticationPlugin;
041import org.nuxeo.runtime.api.Framework;
042import org.nuxeo.runtime.transaction.TransactionHelper;
043
044/**
045 * OAuth2 Authentication Plugin.
046 * <p>
047 * This plugin chekcs the {@code access_token} request parameter or the {@code Authorization: Bearer} request header for
048 * a valid OAuth2 token (checked with the {@link OAuth2ClientService}).
049 *
050 * @since 10.3
051 */
052public class NuxeoOAuth2Authenticator implements NuxeoAuthenticationPlugin {
053
054    private static final Log log = LogFactory.getLog(NuxeoOAuth2Authenticator.class);
055
056    public static final String ACCESS_TOKEN = "access_token";
057
058    public static final String BEARER_SP = "Bearer ";
059
060    protected OAuth2TokenStore tokenStore = new OAuth2TokenStore(TOKEN_SERVICE);
061
062    @Override
063    public void initPlugin(Map<String, String> parameters) {
064        // nothing to init
065    }
066
067    @Override
068    public List<String> getUnAuthenticatedURLPrefix() {
069        return null; // NOSONAR
070    }
071
072    @Override
073    public Boolean needLoginPrompt(HttpServletRequest httpRequest) {
074        return FALSE;
075    }
076
077    @Override
078    public Boolean handleLoginPrompt(HttpServletRequest httpRequest, HttpServletResponse httpResponse, String baseURL) {
079        return FALSE;
080    }
081
082    @Override
083    public UserIdentificationInfo handleRetrieveIdentity(HttpServletRequest request, HttpServletResponse response) {
084        String accessToken = getAccessToken(request);
085        if (accessToken == null) {
086            log.trace("OAuth2 token not found");
087            return null;
088        }
089        NuxeoOAuth2Token token = TransactionHelper.runInTransaction(() -> tokenStore.getToken(accessToken));
090        OAuth2ClientService clientService = Framework.getService(OAuth2ClientService.class);
091        if (token == null) {
092            log.trace("OAuth2 token unknown");
093            return null;
094        }
095        if (token.isExpired()) {
096            log.trace("OAuth2 token expired");
097            return null;
098        }
099        if (!clientService.hasClient(token.getClientId())) {
100            if (log.isTraceEnabled()) {
101                log.trace("OAuth2 token for unknown client: " + token.getClientId());
102            }
103            return null;
104        }
105
106        String username = token.getNuxeoLogin();
107        log.trace("OAuth2 token found for user: " + username);
108        return new UserIdentificationInfo(username);
109    }
110
111    protected String getAccessToken(HttpServletRequest request) {
112        String accessToken = request.getParameter(ACCESS_TOKEN);
113        if (StringUtils.isNotBlank(accessToken)) {
114            log.trace("Found access_token request parameter");
115            return accessToken;
116        }
117        String authorization = request.getHeader(AUTHORIZATION);
118        if (authorization != null && authorization.startsWith(BEARER_SP)) {
119            log.trace("Found Authorization: Bearer request header");
120            return authorization.substring(BEARER_SP.length()).trim();
121        }
122        return null;
123    }
124
125}