001package org.nuxeo.ecm.platform.oauth2.request; 002 003import static org.apache.commons.lang.StringUtils.isBlank; 004import static org.nuxeo.ecm.platform.ui.web.auth.oauth2.NuxeoOAuth2Filter.ERRORS.invalid_request; 005import static org.nuxeo.ecm.platform.ui.web.auth.oauth2.NuxeoOAuth2Filter.ERRORS.server_error; 006import static org.nuxeo.ecm.platform.ui.web.auth.oauth2.NuxeoOAuth2Filter.ERRORS.unauthorized_client; 007import static org.nuxeo.ecm.platform.ui.web.auth.oauth2.NuxeoOAuth2Filter.ERRORS.unsupported_response_type; 008 009import java.io.UnsupportedEncodingException; 010import java.util.Date; 011import java.util.Iterator; 012import java.util.Map; 013import java.util.concurrent.ConcurrentHashMap; 014 015import javax.servlet.http.HttpServletRequest; 016 017import org.apache.commons.lang.RandomStringUtils; 018import org.apache.commons.logging.Log; 019import org.apache.commons.logging.LogFactory; 020import org.nuxeo.ecm.directory.DirectoryException; 021import org.nuxeo.ecm.platform.oauth2.clients.ClientRegistry; 022import org.nuxeo.runtime.api.Framework; 023 024/** 025 * @author <a href="mailto:ak@nuxeo.com">Arnaud Kervern</a> 026 * @since 5.9.2 027 */ 028public class AuthorizationRequest extends Oauth2Request { 029 private static final Log log = LogFactory.getLog(AuthorizationRequest.class); 030 031 protected static Map<String, AuthorizationRequest> requests = new ConcurrentHashMap<>(); 032 033 protected String responseType; 034 035 protected String scope; 036 037 protected String state; 038 039 protected String sessionId; 040 041 protected Date creationDate; 042 043 protected String authorizationCode; 044 045 protected String authorizationKey; 046 047 protected String username; 048 049 public static final String RESPONSE_TYPE = "response_type"; 050 051 public static final String SCOPE = "scope"; 052 053 public static final String STATE = "state"; 054 055 public AuthorizationRequest() { 056 } 057 058 public AuthorizationRequest(HttpServletRequest request) { 059 super(request); 060 responseType = request.getParameter(RESPONSE_TYPE); 061 062 scope = request.getParameter(SCOPE); 063 state = request.getParameter(STATE); 064 sessionId = request.getSession(true).getId(); 065 066 creationDate = new Date(); 067 authorizationKey = RandomStringUtils.random(6, true, false); 068 } 069 070 public String checkError() { 071 // Check mandatory fields 072 if (isBlank(responseType) || isBlank(clientId) || isBlank(redirectUri)) { 073 return invalid_request.toString(); 074 } 075 076 // Check if client exists 077 try { 078 ClientRegistry registry = Framework.getLocalService(ClientRegistry.class); 079 if (!registry.hasClient(clientId)) { 080 return unauthorized_client.toString(); 081 } 082 } catch (DirectoryException e) { 083 log.warn(e, e); 084 return server_error.toString(); 085 } 086 087 // Check request type 088 if (!"code".equals(responseType)) { 089 return unsupported_response_type.toString(); 090 } 091 return null; 092 } 093 094 public boolean isExpired() { 095 // RFC 4.1.2, Authorization code lifetime is 10 096 return new Date().getTime() - creationDate.getTime() > 10 * 60 * 1000; 097 } 098 099 public boolean isValidState(HttpServletRequest request) { 100 return isBlank(getState()) || request.getParameter(STATE).equals(getState()); 101 } 102 103 public String getUsername() { 104 return username; 105 } 106 107 public String getResponseType() { 108 return responseType; 109 } 110 111 public String getScope() { 112 return scope; 113 } 114 115 public String getState() { 116 return state; 117 } 118 119 public String getAuthorizationCode() { 120 if (isBlank(authorizationCode)) { 121 authorizationCode = RandomStringUtils.random(10, true, true); 122 } 123 return authorizationCode; 124 } 125 126 public String getAuthorizationKey() { 127 return authorizationKey; 128 } 129 130 private static void deleteExpiredRequests() { 131 Iterator<AuthorizationRequest> iterator = requests.values().iterator(); 132 AuthorizationRequest req; 133 while (iterator.hasNext() && (req = iterator.next()) != null) { 134 if (req.isExpired()) { 135 requests.remove(req.sessionId); 136 } 137 } 138 } 139 140 public static AuthorizationRequest from(HttpServletRequest request) throws UnsupportedEncodingException { 141 deleteExpiredRequests(); 142 143 String sessionId = request.getSession(true).getId(); 144 if (requests.containsKey(sessionId)) { 145 AuthorizationRequest authRequest = requests.get(sessionId); 146 if (!authRequest.isExpired() && authRequest.isValidState(request)) { 147 return authRequest; 148 } 149 } 150 151 AuthorizationRequest authRequest = new AuthorizationRequest(request); 152 requests.put(sessionId, authRequest); 153 return authRequest; 154 } 155 156 public static AuthorizationRequest fromCode(String authorizationCode) { 157 for (AuthorizationRequest auth : requests.values()) { 158 if (auth.authorizationCode != null && auth.authorizationCode.equals(authorizationCode)) { 159 if (auth.sessionId != null) { 160 requests.remove(auth.sessionId); 161 } 162 return auth.isExpired() ? null : auth; 163 } 164 } 165 return null; 166 } 167 168 public void setUsername(String username) { 169 this.username = username; 170 } 171}