/* * (C) Copyright 2006-2013 Nuxeo SA (http://nuxeo.com/) and others. * * 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. * * Contributors: * Nelson Silva <nelson.silva@inevo.pt> - initial API and implementation * Nuxeo */ package org.nuxeo.ecm.platform.oauth2.openid.auth; import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.LOGIN_ERROR; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuxeo.ecm.core.api.NuxeoException; import org.nuxeo.ecm.platform.api.login.UserIdentificationInfo; import org.nuxeo.ecm.platform.oauth2.openid.OpenIDConnectProvider; import org.nuxeo.ecm.platform.oauth2.openid.OpenIDConnectProviderRegistry; import org.nuxeo.ecm.platform.ui.web.auth.interfaces.NuxeoAuthenticationPlugin; import org.nuxeo.runtime.api.Framework; /** * Authenticator using OpenID to retrieve user identity. * * @author Nelson Silva <nelson.silva@inevo.pt> */ public class OpenIDConnectAuthenticator implements NuxeoAuthenticationPlugin { private static final Log log = LogFactory.getLog(OpenIDConnectAuthenticator.class); public static final String STATE_URL_PARAM_NAME = "state"; public static final String STATE_SESSION_ATTRIBUTE = STATE_URL_PARAM_NAME; public static final String CODE_URL_PARAM_NAME = "code"; public static final String ERROR_URL_PARAM_NAME = "error"; public static final String PROVIDER_URL_PARAM_NAME = "provider"; public static final String USERINFO_KEY = "OPENID_USERINFO"; public static final String PROPERTY_OAUTH_CREATE_USER = "nuxeo.oauth.auth.create.user"; public static final String PROPERTY_SKIP_OAUTH_TOKEN = "nuxeo.skip.oauth.token.state.check"; protected void sendError(HttpServletRequest req, String msg) { req.setAttribute(LOGIN_ERROR, msg); } public UserIdentificationInfo retrieveIdentityFromOAuth(HttpServletRequest req, HttpServletResponse resp) { // Getting the "error" URL parameter String error = req.getParameter(ERROR_URL_PARAM_NAME); // / Checking if there was an error such as the user denied access if (error != null && error.length() > 0) { sendError(req, "There was an error: \"" + error + "\"."); return null; } // Getting the "code" URL parameter String code = req.getParameter(CODE_URL_PARAM_NAME); // Checking conditions on the "code" URL parameter if (code == null || code.isEmpty()) { sendError(req, "There was an error: \"" + code + "\"."); return null; } // Getting the "provider" URL parameter String serviceProviderName = req.getParameter(PROVIDER_URL_PARAM_NAME); // Checking conditions on the "provider" URL parameter if (serviceProviderName == null || serviceProviderName.isEmpty()) { sendError(req, "Missing OpenID Connect Provider ID."); return null; } try { OpenIDConnectProviderRegistry registry = Framework.getLocalService(OpenIDConnectProviderRegistry.class); OpenIDConnectProvider provider = registry.getProvider(serviceProviderName); if (provider == null) { sendError(req, "No service provider called: \"" + serviceProviderName + "\"."); return null; } // Check the state token if (!Framework.isBooleanPropertyTrue(PROPERTY_SKIP_OAUTH_TOKEN) && !provider.verifyStateToken(req)) { sendError(req, "Invalid state parameter."); } // Validate the token String accessToken = provider.getAccessToken(req, code); if (accessToken == null) { return null; } OpenIDUserInfo info = provider.getUserInfo(accessToken); // Store the user info as a key in the request so apps can use it // later in the chain req.setAttribute(USERINFO_KEY, info); UserResolver userResolver = provider.getUserResolver(); String userId; if (Framework.isBooleanPropertyTrue(PROPERTY_OAUTH_CREATE_USER)) { userId = userResolver.findOrCreateNuxeoUser(info); } else { userId = userResolver.findNuxeoUser(info); } if (userId == null) { sendError(req, "No user found with email: \"" + info.getEmail() + "\"."); return null; } return new UserIdentificationInfo(userId, userId); } catch (NuxeoException e) { log.error("Error while retrieve Identity From OAuth", e); } return null; } @Override public List<String> getUnAuthenticatedURLPrefix() { return new ArrayList<String>(); } @Override public UserIdentificationInfo handleRetrieveIdentity(HttpServletRequest httpRequest, HttpServletResponse httpResponse) { String error = httpRequest.getParameter(ERROR_URL_PARAM_NAME); String code = httpRequest.getParameter(CODE_URL_PARAM_NAME); String serviceProviderName = httpRequest.getParameter(PROVIDER_URL_PARAM_NAME); if (serviceProviderName == null) { return null; } if (code == null && error == null) { return null; } UserIdentificationInfo userIdent = retrieveIdentityFromOAuth(httpRequest, httpResponse); if (userIdent != null) { userIdent.setAuthPluginName("TRUSTED_LM"); } return userIdent; } @Override public Boolean handleLoginPrompt(HttpServletRequest httpRequest, HttpServletResponse httpResponse, String baseURL) { return false; } @Override public Boolean needLoginPrompt(HttpServletRequest httpRequest) { return false; } @Override public void initPlugin(Map<String, String> parameters) { } }