001/* 002 * (C) Copyright 2017 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 * Thomas Roger 018 * 019 */ 020package org.nuxeo.ecm.platform.oauth2; 021 022import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED; 023import static org.nuxeo.ecm.platform.oauth2.Constants.TOKEN_SERVICE; 024 025import java.io.IOException; 026import java.security.Principal; 027 028import javax.security.auth.login.LoginContext; 029import javax.security.auth.login.LoginException; 030import javax.servlet.FilterChain; 031import javax.servlet.ServletException; 032import javax.servlet.ServletRequest; 033import javax.servlet.ServletResponse; 034import javax.servlet.http.HttpServletRequest; 035import javax.servlet.http.HttpServletResponse; 036 037import org.apache.commons.lang.StringUtils; 038import org.apache.commons.logging.Log; 039import org.apache.commons.logging.LogFactory; 040import org.nuxeo.ecm.platform.oauth2.clients.OAuth2ClientService; 041import org.nuxeo.ecm.platform.oauth2.tokens.NuxeoOAuth2Token; 042import org.nuxeo.ecm.platform.oauth2.tokens.OAuth2TokenStore; 043import org.nuxeo.ecm.platform.ui.web.auth.NuxeoAuthenticationFilter; 044import org.nuxeo.ecm.platform.ui.web.auth.NuxeoSecuredRequestWrapper; 045import org.nuxeo.ecm.platform.ui.web.auth.interfaces.NuxeoAuthPreFilter; 046import org.nuxeo.runtime.api.Framework; 047import org.nuxeo.runtime.transaction.TransactionHelper; 048 049/** 050 * @author <a href="mailto:ak@nuxeo.com">Arnaud Kervern</a> 051 * @since 5.9.2 052 */ 053public class NuxeoOAuth2Filter implements NuxeoAuthPreFilter { 054 055 private static final Log log = LogFactory.getLog(NuxeoOAuth2Filter.class); 056 057 public static final String ACCESS_TOKEN_PARAM = "access_token"; 058 059 public static final String AUTHORIZATION_HEADER = "Authorization"; 060 061 public static final String BEARER_AUTHENTICATION_SCHEME = "Bearer "; 062 063 protected OAuth2TokenStore tokenStore = new OAuth2TokenStore(TOKEN_SERVICE); 064 065 @Override 066 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 067 throws IOException, ServletException { 068 if (!(request instanceof HttpServletRequest)) { 069 chain.doFilter(request, response); 070 return; 071 } 072 073 HttpServletRequest httpRequest = (HttpServletRequest) request; 074 HttpServletResponse httpResponse = (HttpServletResponse) response; 075 String accessToken = getAccessToken(httpRequest); 076 if (accessToken != null) { 077 processAuthentication(accessToken, httpRequest, httpResponse, chain); 078 } else { 079 chain.doFilter(request, response); 080 } 081 } 082 083 protected void processAuthentication(String accessToken, HttpServletRequest request, HttpServletResponse response, 084 FilterChain chain) throws IOException, ServletException { 085 NuxeoOAuth2Token token = TransactionHelper.runInTransaction(() -> tokenStore.getToken(accessToken)); 086 087 OAuth2ClientService clientService = Framework.getService(OAuth2ClientService.class); 088 if (token == null || token.isExpired() || !clientService.hasClient(token.getClientId())) { 089 response.setStatus(SC_UNAUTHORIZED); 090 return; 091 } 092 093 LoginContext loginContext = buildLoginContext(token); 094 if (loginContext != null) { 095 Principal principal = (Principal) loginContext.getSubject().getPrincipals().toArray()[0]; 096 try { 097 chain.doFilter(new NuxeoSecuredRequestWrapper(request, principal), response); 098 } finally { 099 try { 100 loginContext.logout(); 101 } catch (LoginException e) { 102 log.warn("Error when logging out", e); 103 } 104 } 105 } 106 } 107 108 protected String getAccessToken(HttpServletRequest request) { 109 String accessToken = request.getParameter(ACCESS_TOKEN_PARAM); 110 String authorization = request.getHeader(AUTHORIZATION_HEADER); 111 return StringUtils.isNotBlank(accessToken) ? accessToken 112 : authorization != null && authorization.startsWith(BEARER_AUTHENTICATION_SCHEME) 113 ? authorization.substring(BEARER_AUTHENTICATION_SCHEME.length()).trim() : null; 114 } 115 116 protected LoginContext buildLoginContext(NuxeoOAuth2Token token) { 117 try { 118 return NuxeoAuthenticationFilter.loginAs(token.getNuxeoLogin()); 119 } catch (LoginException e) { 120 log.warn("Error while authenticate user"); 121 } 122 return null; 123 } 124 125}