...
Code Block |
---|
package dk.portalprotect.sample.oauth2; import java.io.IOException; import java.util.Hashtable; import java.util.Properties; import java.util.UUID; import dk.itp.caching.lru.LruCache; import dk.itp.security.authentication.oauth.AbstractOAuth2AuthenticationPlugin; import dk.itp.security.passticket.PTException; import dk.itp.security.passticket.User; import dk.itp.security.passticket.server.AuthErrorCodes; import dk.itp.security.utils.Base64; import dk.portalprotect.oauth.OAuth2Helper; /** * Demonstration OAuth2 plugin - not suitable for production use. * It issues a new ticket by generating a random key and returning it as the grantticket. It then persists the issuing * users ticket and saves it in a memory cache for up to an hour - during that our, the grant ticket gets access to the * previously saved session contents. * * Please note that a production OAuth plugin must take care to validate the provided client_id and ensure that it * already exists in a known registry - it needs to ensure that the client id is valid for the attempted operation, * especially it needs to ensure that implicity grant is only used if explicitly allowed. * * Also, the provided scope must be validated for content which has meaning to the application, and the application * needs to use this information when authorizing a request and allowing access to data on the users behalf. * * @author Kim Rasmussen * @version $Revision$ * * <pre> * PortalProtect - Security infrastructure * Copyright(c) 2014, Asseco Denmark A/S, All rights reserved.Ceptor * * This source code is confidential. * </pre> */ public class DemoOAuth2AuthenticationPlugin extends AbstractOAuth2AuthenticationPlugin { private LruCache cache = new LruCache(); private LruCache authCache = new LruCache(); private class AuthCacheEntry { String bearertoken; String clientid; String clientSecret = "password"; String redirectUri; } public DemoOAuth2AuthenticationPlugin() { cache.setCacheSize(1000); cache.setTimeout(60000*60); // 1 hour cache.setForceTimeout(60000*60); // 1 hour authCache.setCacheSize(1000); authCache.setTimeout(120000); // 2 minutes authCache.setForceTimeout(120000); // 2 minutes } @Override protected Properties validateAuthRequest(User user, Properties input) throws PTException { Properties p = super.validateAuthRequest(user, input); // Validate that client_id / redirect_uri is valid // Could also check if state or other input parameters are valid return p; } @Override protected Properties handleTokenRequest(User user, Properties input) throws PTException { Properties p = validateTokenRequest(user, input); // Exchange authorization_code with a grant token if (OAuth2Helper.AUTHORIZATION_CODE.equals(input.getProperty(OAuth2Helper.GRANT_TYPE))) { String authorizationCode = input.getProperty(OAuth2Helper.CODE); AuthCacheEntry entry = (AuthCacheEntry) authCache.get(authorizationCode); if (entry == null || !entry.clientid.equals(input.getProperty(OAuth2Helper.CLIENT_ID )) || !input.getProperty(OAuth2Helper.CLIENT_SECRET).equals(entry.clientSecret)) { throw new PTException("Invalid authorization_code, client ID or client secret", AuthErrorCodes.ERROR_INVALIDCREDENTIALS, "Invalid authorization_code, client_id or client_secret"); } if (!entry.redirectUri.equals(input.getProperty(OAuth2Helper.REDIRECT_URI ))) { throw new PTException("Invalid redirect URI", AuthErrorCodes.ERROR_INVALIDCREDENTIALS, "Invalid redirect URI"); } p.setProperty(OAuth2Helper.ACCESS_TOKEN, entry.bearertoken); p.setProperty(OAuth2Helper.TOKEN_TYPE, "Bearer"); p.setProperty(OAuth2Helper.EXPIRES_IN, "3600"); // Here, we could also add a refresh_token if we had one to add. } else { // Must be refresh_token, since validateTokenRequest ensures nothing else can pass @SuppressWarnings("unused") String refreshToken = input.getProperty(OAuth2Helper.REFRESH_TOKEN); throw new PTException("Refresh tokens are not supported at the moment", AuthErrorCodes.ERROR_INVALIDCREDENTIALS, "refresh_token not supported"); } return p; } @SuppressWarnings({ "rawtypes", "unchecked" }) @Override protected java.util.Properties handleAuthRequest(dk.itp.security.passticket.User user, java.util.Properties input) throws PTException { Properties p = validateAuthRequest(user, input); String clientid = input.getProperty(OAuth2Helper.CLIENT_ID); // Create a new clone and use this to avoid altering the current users original session User newUser = (User) user.clone(); if (newUser.stateVariables == null) newUser.stateVariables = new Hashtable(); // Save the requested scope for later use when the session is restored newUser.stateVariables.put("pp_oauth2_scope", input.getProperty(OAuth2Helper.SCOPE)); // Save the client ID too for later use newUser.stateVariables.put("pp_oauth2_clientid", input.getProperty(OAuth2Helper.CLIENT_ID)); byte[] persistedSession; try { persistedSession = persistSession(newUser); } catch (IOException e) { throw new PTException(e); } if (input.getProperty(OAuth2Helper.RESPONSE_TYPE).equalsIgnoreCase(OAuth2Helper.CODE)) { // Tell dispatcher to disable IP checking for this particular session(bearer token), since it is meant // to be used by another server instead of the same client newUser.stateVariables.put("pp_disable_ipchecking", "true"); } String bearertoken = Base64.encode(UUID.randomUUID().toString()); cache.put(bearertoken, persistedSession); if (input.getProperty(OAuth2Helper.RESPONSE_TYPE).equalsIgnoreCase(OAuth2Helper.TOKEN)) { // Implicit grant p.setProperty(OAuth2Helper.ACCESS_TOKEN, bearertoken); p.setProperty(OAuth2Helper.TOKEN_TYPE, "Bearer"); p.setProperty(OAuth2Helper.EXPIRES_IN, "3600"); return p; } else { // Normal flow String authorizationToken = UUID.randomUUID().toString(); AuthCacheEntry entry = new AuthCacheEntry(); entry.bearertoken = bearertoken; entry.clientid = clientid; entry.redirectUri = input.getProperty(OAuth2Helper.REDIRECT_URI); authCache.put(authorizationToken, entry); p.setProperty(OAuth2Helper.AUTHORIZATION_CODE, authorizationToken); return p; } } @Override public void createFromTicket(User user) throws PTException { // Ticket is in user.ticket byte[] ba = (byte[]) cache.get(user.ticket); if (ba == null) throw new PTException("Invalid OAuth ticket", AuthErrorCodes.ERROR_INVALIDCREDENTIALS, "Invalid or expired OAuth ticket"); try { User restoredUser = restorePersistedSession(ba); // Save the ticket and session ID so we do not overwrite them restoredUser.ticket = user.ticket; restoredUser.sessionID = user.sessionID; // Restore everything from the persisted session to this one restoredUser.copyTo(user); user.addHistory("Session restored from persisted session using OAuth ticket: " + user.ticket); } catch (IOException e) { throw new PTException("Unable to restore persisted session", AuthErrorCodes.ERROR_GENERALERROR, "Unable to restore session", e); } } } |
...