diff --git a/external-authn/README.md b/external-authn/README.md new file mode 100644 index 0000000000..46a48e354a --- /dev/null +++ b/external-authn/README.md @@ -0,0 +1,150 @@ +# External Authn + +## Design +``` +Title External Authn + +actor Person +participant Browser +participant Website1 +participant Website2 +participant IDP +database cache + +Person->Browser: 1. Navigate to website1 +Browser->Website1: +Website1->Browser: 2. redirect +group Person Authn Script : Step One +Browser->IDP: 3. [GET] /oxauth/authorize?client_id=__&redirect_uri=__&state=__\n&nonce=__&prompt=none&scope=__\n&response_mode=__&response_type=__ +IDP->IDP: 4. generate jans_key +IDP<->cache: cache in session context\njans_key: {request params} +IDP->Browser: 5. redirect /internal.idp?________\nSet Pre-Authn Session Cookie +Browser->Website2: +end +Website2->Browser: 6. Display login page +Person->Browser: 7. Enter Username / PW +Browser->Website2: 8. (creds) +group ROPW script +Website2->IDP: 9. /oxauth/token?uid=__&pw="__&browser_ip=__&jans_key=__ +IDP->IDP: 10. update cache:\n "jans_key": "auth_success" +IDP->IDP: 11. retreive user claims +IDP->Website2:12. {\n "callback_url":"https://op-host/oxauth**/authorize?jansKey={jansKey}&redirect_uri={original_redirect}&...**",\n "userinfo": {"uid": "__",...}\n } +end +group Person Authn Script Step 2 +Website2->Browser: 13. write website 2 cookie;\n302 Location IDP callback_url +Browser->IDP: 14. callback_url_from_step_12 +IDP->IDP: 15. get session context +IDP->cache:16. delete jans_key\n lookup original redirect_uri +IDP->Browser: 17. write IDP session cookie\nand 302: Location original redirect_uri +end +Browser->Website1: +Website1->Website1: optional: 18 Validate id_token\n (claims optional) +``` +![](assets/external-authn-diagram.png) + +Follow the instructions below to set up: + +## OxAuth Configuration +Enable **openidScopeBackwardCompatibility** +![openidScopeBackwardCompatibility](assets/openidscope-bc.png) + +Add new custom param **jansKey** +![custom param jansKey](assets/janskey-custom-param.png) + +## Enable Custom Script + +- ### Person Authentication - External Authn + +Create a new record in table **oxCustomScript**. +``` +INSERT INTO oxCustomScript ( doc_id, objectClass, dn, displayName, oxEnabled, oxRevision, oxScript, oxAlias, oxScriptType, oxModuleProperty, programmingLanguage, oxScriptError, oxConfigurationProperty, inum, description, oxLevel ) +VALUES ( 'PA01-EA01', 'oxCustomScript', 'inum=PA01-EA01,ou=scripts,o=gluu', 'pa-external-authn', 0, 1, '', '{"v": []}', 'person_authentication', '{"v": ["{\\"value1\\":\\"usage_type\\",\\"value2\\":\\"interactive\\",\\"description\\":\\"\\"}", "{\\"value1\\":\\"location_type\\",\\"value2\\":\\"ldap\\",\\"description\\":\\"\\"}"]}', 'python', NULL, '{"v": ["{\\"value1\\":\\"urlstep1\\",\\"value2\\":\\"http://demoexample.net:81\\",\\"hide\\":false,\\"description\\":\\"Url to return in step 1\\"}"]}', 'PA01-EA01', 'PA External Authn', 10 ); +``` + +Modify the **oxConfigurationProperty** field by replacing **URL_REDIRECT_URI** with the url that you want to return to the first step +``` +'{"v": ["{\\"value1\\":\\"urlstep1\\",\\"value2\\":\\"{URL_REDIRECT_URI}\\",\\"hide\\":false,\\"description\\":\\"Url to return in step 1\\"}"]}' +``` +![](assets/pa-property.png) + +Modify the **oxScript** field by adding the content of the following link: [PersonAuthentication Script](pyscript/pa-external-authn.py) + +- ### ROPC (Resource Owner Password Credentials) Script - External Authn + +Create a new record in table **oxCustomScript**. +``` +INSERT INTO oxCustomScript ( doc_id, objectClass, dn, displayName, oxEnabled, oxRevision, oxScript, oxAlias, oxScriptType, oxModuleProperty, programmingLanguage, oxScriptError, oxConfigurationProperty, inum, description, oxLevel ) +VALUES ( 'ROPC-EA01', 'oxCustomScript', 'inum=ROPC-EA01,ou=scripts,o=gluu', 'ropc-external-authn', 0, 1, '', '{"v": []}', 'resource_owner_password_credentials', '{"v": ["{\\"value1\\":\\"location_type\\",\\"value2\\":\\"ldap\\",\\"description\\":\\"\\"}"]}', 'python', NULL, '{"v": []}', 'ROPC-EA01', 'ROPC External Authn', 1 ); +``` + +Modify the **oxScript** field by adding the content of the following link: [ROPC (Resource Owner Password Credentials) Script](pyscript/ropc-external-authn.py) + +- ### Update Token Script - External Authn + +Create a new record in table **oxCustomScript**. +``` +INSERT INTO oxCustomScript ( doc_id, objectClass, dn, displayName, oxEnabled, oxRevision, oxScript, oxAlias, oxScriptType, oxModuleProperty, programmingLanguage, oxScriptError, oxConfigurationProperty, inum, description, oxLevel ) +VALUES ( 'UPDT-EA01', 'oxCustomScript', 'inum=UPDT-EA01,ou=scripts,o=gluu', 'update-token-external-authn', 0, 1, '', '{"v": []}', 'update_token', '{"v": ["{\\"value1\\":\\"location_type\\",\\"value2\\":\\"ldap\\",\\"description\\":\\"\\"}"]}', 'python', NULL, '{"v": []}', 'UPDT-EA01', 'Update token External Authn', 1 ); +``` + +Modify the **oxScript** field by adding the content of the following link: [Update Token Script](pyscript/ut-external-authn.py) + +In this script you can choose whether to use the header or payload of the **id_token** for the **callback_url**: +``` +jsonWebResponse.getHeader().setClaim("callback_url", jsonValCallbackUrl) +jsonWebResponse.getClaims().setClaim("callback_url", jsonValCallbackUrl) +``` + +## Client Configuration +Enable acr default values, add the previously configured custom script +![](assets/client-config-external-aux.png) + +Enable **PreAuthorization** +![PreAuthorization](assets/client-preauthz.png) + +## Call Flow +- ### Step 1: /authorize +Request: +``` +curl --location --request GET 'https://{your-gluu-url}/oxauth/restv1/authorize?response_type=code&client_id=14e36e18-1d51-41ac-a4cf-a7dc677f53a5&scope=openid+profile+address+email&redirect_uri=https://jans.localhost/jans-auth-rp/home.htm&state=a84dd61f-533c-46a4-9315-a66fda3e9a4e&nonce=80e6bd2b-eb78-48b9-be9c-6bb33ef80991&ui_locales=&claims_locales=&request_session_id=false&acr_values=' +``` +Response: (return the **redirect_uri** with jansKey) +``` +http://demoexample.net:81?jansKey=46340f40-a554-46b1-9246-37c2e869919f +``` + +- ### Step 2: /token +Request: (**Authorization** = Basic base64(client_id:client_secret)) +``` +curl --location --request POST 'https://{your-gluu-url}/oxauth/restv1/token' \ +--header 'Authorization: Basic MTRlMzZlMTgtMWQ1MS00MWFjLWE0Y2YtYTdkYzY3N2Y1M2E1Ojk5NzE4NWU1LTc2NGUtNGE4Yi1hNjYwLTdjZmQ4NzJhNjc0Ng==' \ +--header 'Content-Type: application/x-www-form-urlencoded' \ +--data-urlencode 'grant_type=password' \ +--data-urlencode 'username=test_user' \ +--data-urlencode 'password=test_user_password' \ +--data-urlencode 'scope=openid' \ +--data-urlencode 'jansKey=46340f40-a554-46b1-9246-37c2e869919f' +``` +Response: (id_token contains in header or payload callback_url) +``` +{ + "access_token": "a0878887-b998-4da4-aa0b-4e74bd9a4441", + "refresh_token": "d8b618ac-9d9c-4b90-9cac-aafb1e38e82e", + "scope": "openid", + "id_token": "eyJjYWxsYmFja191cmwiOiJodHRwczovL2RlbW9leGFtcGxlLmdsdXUub3JnL294YXV0aC9yZXN0djEvYXV0aG9yaXplP3Jlc3BvbnNlX3R5cGU9Y29kZSZyZWRpcmVjdF91cmk9aHR0cHMlM0ElMkYlMkZkZW1vZXhhbXBsZS5nbHV1Lm9yZyUyRm94YXV0aC1ycCUyRmhvbWUuaHRtJmphbnNLZXk9MGZiZmU2ZmUtY2YzZi00NGU3LWE0MzMtNjE3OWMzNTk4OTAzJmNsaWVudF9pZD1jZjlhOGExMC00MWJlLTQ0OTEtODdlNC1mY2MxMDlmOGRhMmMiLCJraWQiOiJmOTllNzVmMy1jYWQ4LTRmMzgtYTdlYi05Njc0ZWRjYTA5NGRfc2lnX3JzMjU2IiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ.eyJjYWxsYmFja191cmwiOiJodHRwczovL2RlbW9leGFtcGxlLmdsdXUub3JnL294YXV0aC9yZXN0djEvYXV0aG9yaXplP3Jlc3BvbnNlX3R5cGU9Y29kZSZyZWRpcmVjdF91cmk9aHR0cHMlM0ElMkYlMkZkZW1vZXhhbXBsZS5nbHV1Lm9yZyUyRm94YXV0aC1ycCUyRmhvbWUuaHRtJmphbnNLZXk9MGZiZmU2ZmUtY2YzZi00NGU3LWE0MzMtNjE3OWMzNTk4OTAzJmNsaWVudF9pZD1jZjlhOGExMC00MWJlLTQ0OTEtODdlNC1mY2MxMDlmOGRhMmMiLCJhdWQiOiJjZjlhOGExMC00MWJlLTQ0OTEtODdlNC1mY2MxMDlmOGRhMmMiLCJhY3IiOiJzaW1wbGVfcGFzc3dvcmRfYXV0aCIsInN1YiI6IjAzNEp3b1dtNEgxUFVyLThrMEdTQzI2NWxPS2s4Z3ljTHN5MDVlbUhjNEUiLCJjb2RlIjoiZTYxYzViYmEtNTk1OC00ODk3LTg4MTItNmU5MDAwMDE1NWRmIiwiYW1yIjpbIi0xIl0sImlzcyI6Imh0dHBzOi8vZGVtb2V4YW1wbGUuZ2x1dS5vcmciLCJleHAiOjE2NjEzNDYyNDMsImdyYW50IjoicGFzc3dvcmQiLCJpYXQiOjE2NjEzNDI2NDMsInNpZCI6ImRhOTIxZWI2LTQ1MGItNGJlMC05ODI4LTM4ZWQ2NTcyNmVjYiIsIm94T3BlbklEQ29ubmVjdFZlcnNpb24iOiJvcGVuaWRjb25uZWN0LTEuMCJ9.mffKKvsGWV1qmUy98B7H9RCR-4usP8jOsGEif419prR2cN9fWRSSFC7WTJr6Myh5EEJDAb_tQnA9TSTtP5XlTP41B9l02RMvJINCMYnBlUbP5L6WzowH4N3j7CH6V96ruM_w-dAoeqgAmbMCQCG1b5BQQjZntE16GQOvUnA6IukbKBv5vzPQn74cxhIKYL6b6BePT4oiQ2WOdbQqGEBFPHebmzLzGoIK60YgSr3qToZHt3WUP0TbTEpcvQb9oAaanCdjdP12Y6gZOqQK452GmygCZxZ_8wnFENAWF4rj85kdCFu5ucM40n-K7RpAclPPCGU_hJTKGr0BfOGIPOP3OA", + "token_type": "Bearer", + "expires_in": 299 +} +``` + +- ### Step 3: callback_uri (/authorize) + +Request: +``` +curl --location --request GET 'https://{your-gluu-url}/oxauth/restv1/authorize?response_type=code&redirect_uri=https%3A%2F%2Fjans.localhost%2Fjans-auth-rp%2Fhome.htm&client_id=14e36e18-1d51-41ac-a4cf-a7dc677f53a5&jansKey=46340f40-a554-46b1-9246-37c2e869919f' +``` + +Response: (return to the **redirect_uri**) +``` +https://jans.localhost/jans-auth-rp/home.htm?code=441688df-8f36-4e2c-8174-18d23cc88049&acr_values=pa-external-authn&session_id=7ee59d72-d59a-49ce-a0cb-19c4fcfc404c&session_state=c3f595a892208e3d237722ad06d830f199295ccc355827c436fff71509401eae.a505421b-a332-4604-8772-6ca345c4a4b9 +``` \ No newline at end of file diff --git a/external-authn/assets/client-config-external-aux.png b/external-authn/assets/client-config-external-aux.png new file mode 100644 index 0000000000..3a82806f96 Binary files /dev/null and b/external-authn/assets/client-config-external-aux.png differ diff --git a/external-authn/assets/client-preauthz.png b/external-authn/assets/client-preauthz.png new file mode 100644 index 0000000000..4718438739 Binary files /dev/null and b/external-authn/assets/client-preauthz.png differ diff --git a/external-authn/assets/external-authn-diagram.png b/external-authn/assets/external-authn-diagram.png new file mode 100644 index 0000000000..5e774d6dbb Binary files /dev/null and b/external-authn/assets/external-authn-diagram.png differ diff --git a/external-authn/assets/janskey-custom-param.png b/external-authn/assets/janskey-custom-param.png new file mode 100644 index 0000000000..14b60b43bd Binary files /dev/null and b/external-authn/assets/janskey-custom-param.png differ diff --git a/external-authn/assets/openidscope-bc.png b/external-authn/assets/openidscope-bc.png new file mode 100644 index 0000000000..c70aad0257 Binary files /dev/null and b/external-authn/assets/openidscope-bc.png differ diff --git a/external-authn/assets/pa-property.png b/external-authn/assets/pa-property.png new file mode 100644 index 0000000000..01b03aa6c4 Binary files /dev/null and b/external-authn/assets/pa-property.png differ diff --git a/external-authn/pyscript/pa-external-authn.py b/external-authn/pyscript/pa-external-authn.py new file mode 100644 index 0000000000..0a03b84939 --- /dev/null +++ b/external-authn/pyscript/pa-external-authn.py @@ -0,0 +1,180 @@ +# PersonAuthentication External Authn + +from org.gluu.model.custom.script.type.auth import PersonAuthenticationType +from org.gluu.service.cdi.util import CdiUtil +from org.gluu.oxauth.security import Identity +from org.gluu.oxauth.service import AuthenticationService +from org.gluu.util import StringHelper +from org.gluu.oxauth.util import ServerUtil +from org.gluu.oxauth.service import SessionIdService +from org.gluu.oxauth.service import CookieService +from org.gluu.service.cache import CacheProvider +from javax.faces.context import ExternalContext +from java.util import HashMap +from org.gluu.oxauth.service import UserService, RequestParameterService +from org.gluu.oxauth.service.net import HttpService +from javax.faces.context import FacesContext +from org.gluu.jsf2.service import FacesService + +import java +import uuid + +class PersonAuthentication(PersonAuthenticationType): + def __init__(self, currentTimeMillis): + self.currentTimeMillis = currentTimeMillis + + def init(self, customScript, configurationAttributes): + print "PA External Authn. Initialization" + print "PA External Authn. Initialized successfully configurationAttributes = %s" % configurationAttributes + + self.url_step1 = None + + # Get Custom Properties + try: + self.url_step1 = configurationAttributes.get("urlstep1").getValue2() + print "PA External Authn. Initialization. url_step1: '%s'" % self.url_step1 + except: + print 'Missing required configuration attribute "urlstep1"' + + return True + + def destroy(self, configurationAttributes): + print "PA External Authn. Destroy" + print "PA External Authn. Destroyed successfully" + return True + + def getAuthenticationMethodClaims(self, requestParameters): + return None + + def getApiVersion(self): + return 11 + + def isValidAuthenticationMethod(self, usageType, configurationAttributes): + return True + + def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): + return None + + def authenticate(self, configurationAttributes, requestParameters, step): + print "PA External Authn. Authenticate, step: %s, requestParameters: %s" % (step, requestParameters) + + # Retrieve jansKey from request params + jansKey = ServerUtil.getFirstValue(requestParameters, "jansKey") + if (jansKey == None): + print "PA External Authn. Authenticate. Could not find jansKey in request param" + return False + print "PA External Authn. Authenticate. jansKey found in request param: '%s'" % jansKey + + # Retrieve jsonValues from cache + cacheProvider = CdiUtil.bean(CacheProvider) + jsonValues = cacheProvider.get(jansKey) + if (jsonValues == None): + print "PA External Authn. Authenticate. Could not find jsonValues in cache" + return False + print "PA External Authn. Authenticate. jsonValues found in cache: %s" % jsonValues + + # Retrieve sessionDn from cacheProvider + sessionDn = jsonValues.get("sessionDn") + if (sessionDn == None): + print "PA External Authn. Authenticate. Could not find sessionDn in cache" + return False + print "PA External Authn. Authenticate. sessionDn found in cache: '%s'" % sessionDn + + # Retrieve sessionId by dn + sessionId = CdiUtil.bean(SessionIdService).getSessionByDn(sessionDn) + if (sessionId == None): + print "PA External Authn. Authenticate. Could not find sessionId by dn: '%s'" % sessionDn + return False + print "PA External Authn. Authenticate. sessionId found by dn: '%s'" % sessionId.getId() + + # Write sessionId in cookies + cookieService = CdiUtil.bean(CookieService) + cookieService.createSessionIdCookie(sessionId, False) + print "PA External Authn. Authenticate. Writed session in cookies" + + # Set sessionId in Identity + identity = CdiUtil.bean(Identity) + identity.setSessionId(sessionId) + print "PA External Authn. Authenticate. Setted session in identity" + + # Remove jansKey from cache + cacheProvider.remove(jansKey) + print "PA External Authn. Authenticate. jansKey removed from cache" + + return True + + def prepareForStep(self, configurationAttributes, requestParameters, step): + if (step == 1): + return True + else: + return False + + def getExtraParametersForStep(self, configurationAttributes, step): + return None + + def getCountAuthenticationSteps(self, configurationAttributes): + return 1 + + def getPageForStep(self, configurationAttributes, step): + print "PA External Authn. GetPageForStep step: %s" % step + + externalContext = CdiUtil.bean(ExternalContext) + jansKeyParam = ServerUtil.getFirstValue(externalContext.getRequestParameterValuesMap(), "jansKey") + if (jansKeyParam == None): + print "PA External Authn. GetPageForStep could not found jansKey in request param" + + # Remove session id cookie + cookieService = CdiUtil.bean(CookieService) + cookieService.removeSessionIdCookie(externalContext.getResponse()) + print "PA External Authn. GetPageForStep remove session id cookie" + + # Retrieve redirectUri from request param and validate it + redirectUri = ServerUtil.getFirstValue(externalContext.getRequestParameterValuesMap(), "redirect_uri") + if (redirectUri == None or StringHelper.isEmpty(redirectUri)): + print "PA External Authn. GetPageForStep redirect_uri is null or empty" + return "" + print "PA External Authn. GetPageForStep redirect_uri '%s' found in request param" % redirectUri + + clientId = ServerUtil.getFirstValue(externalContext.getRequestParameterValuesMap(), "client_id") + if (clientId == None or StringHelper.isEmpty(clientId)): + print "PA External Authn. GetPageForStep client_id is null or empty" + return "" + print "PA External Authn. GetPageForStep client_id '%s' found in request param" % clientId + + # Generate jansKey + jansKey = str(uuid.uuid4()) + print "PA External Authn. GetPageForStep jansKey '%s' generated" % jansKey + + # Create JSON Values + jsonValues = {} + jsonValues["redirectUri"] = str(redirectUri) + jsonValues["clientId"] = str(clientId) + + cacheProvider = CdiUtil.bean(CacheProvider) + cacheProvider.put(300, jansKey, jsonValues) + print "PA External Authn. GetPageForStep jansKey '%s' added to cache: %s" % (jansKey, jsonValues) + + requestParameterService = CdiUtil.bean(RequestParameterService) + parametersMap = HashMap() + parametersMap.put("jansKey", jansKey) + callBackUrl = requestParameterService.parametersAsString(parametersMap) + callBackUrl = "%s?%s" % (self.url_step1, callBackUrl) + + print "PA External Authn. GetPageForStep redirect to %s" % callBackUrl + + facesService = CdiUtil.bean(FacesService) + facesService.redirectToExternalURL(callBackUrl) + + return "" + + print "PA External Authn. GetPageForStep jansKey found in request param: %s" % jansKeyParam + return "postlogin.xhtml" + + def getNextStep(self, configurationAttributes, requestParameters, step): + return -1 + + def getLogoutExternalUrl(self, configurationAttributes, requestParameters): + return None + + def logout(self, configurationAttributes, requestParameters): + return True diff --git a/external-authn/pyscript/ropc-external-authn.py b/external-authn/pyscript/ropc-external-authn.py new file mode 100644 index 0000000000..bfb037dd0d --- /dev/null +++ b/external-authn/pyscript/ropc-external-authn.py @@ -0,0 +1,144 @@ +# ResourceOwnerPasswordCredentials External Authn + +from org.gluu.model.custom.script.type.owner import ResourceOwnerPasswordCredentialsType +from org.gluu.oxauth.service import AuthenticationService, SessionIdService +from org.gluu.oxauth.model.common import SessionIdState +from org.gluu.oxauth.security import Identity +from org.gluu.service.cdi.util import CdiUtil +from org.gluu.oxauth.model.authorize import AuthorizeRequestParam +from org.gluu.oxauth.model.config import Constants +from org.gluu.util import StringHelper +from java.lang import String +from java.util import Date, HashMap +from org.gluu.service.cache import CacheProvider + +from org.gluu.oxauth.service import RequestParameterService +from org.gluu.oxauth.service.net import HttpService +from javax.faces.context import FacesContext +from org.gluu.jsf2.service import FacesService + +class ResourceOwnerPasswordCredentials(ResourceOwnerPasswordCredentialsType): + def __init__(self, currentTimeMillis): + self.currentTimeMillis = currentTimeMillis + + def init(self, customScript, configurationAttributes): + print "ROPC External Authn. Initializing ..." + print "ROPC External Authn. Initialized successfully" + return True + + def destroy(self, configurationAttributes): + print "ROPC External Authn. Destroying ..." + print "ROPC External Authn. Destroyed successfully" + return True + + def getApiVersion(self): + return 11 + + def authenticate(self, context): + print "ROPC External Authn. Authenticate" + + # Retrieve jansKey from request parameters + jansKey = context.getHttpRequest().getParameter("jansKey") + if (jansKey == None or StringHelper.isEmpty(jansKey)): + print "ROPC External Authn. Authenticate. jansKey not found or empty" + return False + print "ROPC External Authn. Authenticate. jansKey '%s' found in request" % jansKey + + cacheProvider = CdiUtil.bean(CacheProvider) + jsonValues = cacheProvider.get(jansKey) + if (jsonValues == None): + print "ROPC External Authn. Authenticate. Could not find jsonValues in cache" + return False + print "ROPC External Authn. Authenticate. jsonValues found in cache" + + # Do generic authentication + authenticationService = CdiUtil.bean(AuthenticationService) + + username = context.getHttpRequest().getParameter("username") + password = context.getHttpRequest().getParameter("password") + result = authenticationService.authenticate(username, password) + if not result: + print "ROPC External Authn. Authenticate. Could not authenticate user '%s' " % username + return False + + context.setUser(authenticationService.getAuthenticatedUser()) + print "ROPC External Authn. Authenticate. User '%s' authenticated successfully" % username + + # Get cusom parameters from request + customParam1Value = context.getHttpRequest().getParameter("custom1") + customParam2Value = context.getHttpRequest().getParameter("custom2") + + customParameters = {} + customParameters["custom1"] = customParam1Value + customParameters["custom2"] = customParam2Value + print "ROPC External Authn. Authenticate. User '%s'. Creating authenticated session with custom attributes: '%s'" % (username, customParameters) + + session = self.createNewAuthenticatedSession(context, customParameters) + + # This is needed to allow store in token entry sessionId + authenticationService.configureEventUser(session) + print "ROPC External Authn. Authenticate. User '%s'. Created authenticated session: '%s'" % (username, customParameters) + + callbackUrl = self.createCallbackUrl(context, jansKey, session, jsonValues) + if (callbackUrl != None and StringHelper.isNotEmpty(callbackUrl)): + jsonValues["callbackUrl"] = str(callbackUrl) + jsonValues["sessionDn"] = session.getDn() + cacheProvider.put(300, jansKey, jsonValues) + print "ROPC External Authn. Authenticate. jsonValues stored in cache: '%s'" % jsonValues + + return True + + def createNewAuthenticatedSession(self, context, customParameters={}): + sessionIdService = CdiUtil.bean(SessionIdService) + + user = context.getUser() + client = CdiUtil.bean(Identity).getSessionClient().getClient() + + # Add mandatory session parameters + sessionAttributes = HashMap() + sessionAttributes.put(Constants.AUTHENTICATED_USER, user.getUserId()) + sessionAttributes.put(AuthorizeRequestParam.CLIENT_ID, client.getClientId()) + sessionAttributes.put(AuthorizeRequestParam.PROMPT, "") + + # Add custom session parameters + for key, value in customParameters.iteritems(): + if StringHelper.isNotEmpty(value): + sessionAttributes.put(key, value) + + # Generate authenticated session + sessionId = sessionIdService.generateAuthenticatedSessionId(context.getHttpRequest(), user.getDn(), sessionAttributes) + + print "ROPC External Authn. Generated sessionId. DN: '%s'" % sessionId.getDn() + + return sessionId + + def createCallbackUrl(self, context, jansKey, sessionId={}, jsonValues={}): + # Retrieve redirectUri from cache using jansKey + jsonValRedirectUri = jsonValues.get("redirectUri") + if (jsonValRedirectUri == None): + print "ROPC External Authn. CreateCallbackUrl. redirectUri not found in cache" + return "" + print "ROPC External Authn. CreateCallbackUrl. redirectUri found '%s' in cache" % jsonValRedirectUri + + # Retrieve clientId from cache using jansKey + jsonValClientId = jsonValues.get("clientId") + if (jsonValClientId == None): + print "ROPC External Authn. CreateCallbackUrl. clientId not found in cache" + return "" + print "ROPC External Authn. CreateCallbackUrl. clientId found '%s' in cache" % jsonValClientId + + parameterMap = HashMap() + parameterMap.put("response_type", "code") + parameterMap.put("client_id", jsonValClientId) + parameterMap.put("redirect_uri", jsonValRedirectUri) + parameterMap.put("jansKey", jansKey) + + requestParameterService = CdiUtil.bean(RequestParameterService) + parameterString = requestParameterService.parametersAsString(parameterMap) + + authorizeEndpoint = context.getAppConfiguration().getAuthorizationEndpoint() + jansUrl = "%s?%s" % (authorizeEndpoint, parameterString) + + print "ROPC External Authn. CreateCallbackUrl. jansUrl '%s'" % jansUrl + + return jansUrl \ No newline at end of file diff --git a/external-authn/pyscript/ut-external-authn.py b/external-authn/pyscript/ut-external-authn.py new file mode 100644 index 0000000000..5b4bdee4f6 --- /dev/null +++ b/external-authn/pyscript/ut-external-authn.py @@ -0,0 +1,69 @@ +# UpdateToken External Authn + +from org.gluu.model.custom.script.type.token import UpdateTokenType +from org.gluu.service.cache import CacheProvider +from org.gluu.service.cdi.util import CdiUtil +from org.gluu.util import StringHelper + +class UpdateToken(UpdateTokenType): + def __init__(self, currentTimeMillis): + self.currentTimeMillis = currentTimeMillis + + def init(self, customScript, configurationAttributes): + print "UT External Authn. Initializing ..." + print "UT External Authn. Initialized successfully" + + return True + + def destroy(self, configurationAttributes): + print "UT External Authn. Destroying ..." + print "UT External Authn. Destroyed successfully" + return True + + def getApiVersion(self): + return 11 + + def modifyIdToken(self, jsonWebResponse, context): + + # Retrieve jansKey from cache + jansKey = context.getHttpRequest().getParameter("jansKey") + if (jansKey == None or StringHelper.isEmpty(jansKey)): + print "UT External Authn. ModifyIdToken Could not find jansKey in request" + return False + print "UT External Authn. ModifyIdToken jansKey '%s' found in request" % jansKey + + # Retrieve jsonValues from cache using jansKey + cacheProvider = CdiUtil.bean(CacheProvider) + jsonValues = cacheProvider.get(jansKey) + if (jsonValues == None): + print "UT External Authn. ModifyIdToken Could not find jansKey in cache" + return False + print "UT External Authn. ModifyIdToken jansKey found in cache" + + # Retrieve redirectUri from cache using jansKey + jsonValCallbackUrl = jsonValues.get("callbackUrl") + if (jsonValCallbackUrl == None): + print "UT External Authn. ModifyIdToken Could not find callbackUrl in cache" + return False + print "UT External Authn. ModifyIdToken callbackUrl '%s' found in cache" % jsonValCallbackUrl + + # Decide where to set the callback_uri in header or payload + jsonWebResponse.getHeader().setClaim("callback_url", jsonValCallbackUrl) + jsonWebResponse.getClaims().setClaim("callback_url", jsonValCallbackUrl) + + return True + + def modifyRefreshToken(self, refreshToken, context): + return True + + def modifyAccessToken(self, accessToken, context): + return True + + def getRefreshTokenLifetimeInSeconds(self, context): + return 0 + + def getIdTokenLifetimeInSeconds(self, context): + return 0 + + def getAccessTokenLifetimeInSeconds(self, context): + return 0