From 6185bed203f52f4aec571fd26c55528c66abdb4f Mon Sep 17 00:00:00 2001 From: jgomer2001 Date: Mon, 18 Mar 2024 11:45:20 -0500 Subject: [PATCH 1/4] feat: add accts linking agama project #7556 Signed-off-by: jgomer2001 --- jans-casa/plugins/acct-linking/extras/Casa.py | 737 ++++++++++++++++++ .../io.jans.casa.acctlinking.Launcher.flow | 65 ++ .../io/jans/casa/acctlinking/Mappings.java | 71 ++ .../io/jans/casa/acctlinking/UidUtils.java | 83 ++ .../acct-linking/extras/agama/project.json | 58 ++ .../acct-linking/extras/agama/web/apple.png | Bin 0 -> 8171 bytes .../extras/agama/web/email-prompt.ftlh | 50 ++ .../extras/agama/web/facebook.png | Bin 0 -> 4822 bytes .../acct-linking/extras/agama/web/github.png | Bin 0 -> 29968 bytes .../acct-linking/extras/agama/web/google.png | Bin 0 -> 105019 bytes .../acct-linking/extras/agama/web/none.png | Bin 0 -> 493 bytes .../plugins/acct-linking/extras/login.xhtml | 147 ++++ 12 files changed, 1211 insertions(+) create mode 100644 jans-casa/plugins/acct-linking/extras/Casa.py create mode 100644 jans-casa/plugins/acct-linking/extras/agama/code/io.jans.casa.acctlinking.Launcher.flow create mode 100644 jans-casa/plugins/acct-linking/extras/agama/lib/io/jans/casa/acctlinking/Mappings.java create mode 100644 jans-casa/plugins/acct-linking/extras/agama/lib/io/jans/casa/acctlinking/UidUtils.java create mode 100644 jans-casa/plugins/acct-linking/extras/agama/project.json create mode 100644 jans-casa/plugins/acct-linking/extras/agama/web/apple.png create mode 100644 jans-casa/plugins/acct-linking/extras/agama/web/email-prompt.ftlh create mode 100644 jans-casa/plugins/acct-linking/extras/agama/web/facebook.png create mode 100644 jans-casa/plugins/acct-linking/extras/agama/web/github.png create mode 100644 jans-casa/plugins/acct-linking/extras/agama/web/google.png create mode 100644 jans-casa/plugins/acct-linking/extras/agama/web/none.png create mode 100644 jans-casa/plugins/acct-linking/extras/login.xhtml diff --git a/jans-casa/plugins/acct-linking/extras/Casa.py b/jans-casa/plugins/acct-linking/extras/Casa.py new file mode 100644 index 00000000000..78effa96724 --- /dev/null +++ b/jans-casa/plugins/acct-linking/extras/Casa.py @@ -0,0 +1,737 @@ + +from io.jans.agama.model import Flow +from io.jans.as.server.security import Identity +from io.jans.as.server.service import AuthenticationService +from io.jans.as.server.service import UserService +from io.jans.config import GluuConfiguration +from io.jans.as.server.service.custom import CustomScriptService +from io.jans.as.server.service.net import HttpService +from io.jans.as.server.util import ServerUtil +from io.jans.casa.model import ApplicationConfiguration +from io.jans.jsf2.service import FacesService +from io.jans.model import SimpleCustomProperty +from io.jans.model.custom.script import CustomScriptType +from io.jans.model.custom.script.type.auth import PersonAuthenticationType +from io.jans.orm import PersistenceEntryManager +from io.jans.service import EncryptionService +from io.jans.service import CacheService +from io.jans.service.cdi.util import CdiUtil +from io.jans.util import StringHelper + +from java.lang import Integer +from java.util import Collections, HashMap, HashSet, ArrayList, Arrays, Date +from java.nio.charset import Charset +from java.net import URLEncoder + +from org.apache.http.params import CoreConnectionPNames + +try: + import json +except ImportError: + import simplejson as json +import sys + +class PersonAuthentication(PersonAuthenticationType): + + def __init__(self, currentTimeMillis): + self.currentTimeMillis = currentTimeMillis + self.ACR_SG = "super_gluu" + + self.modulePrefix = "casa-external_" + + def init(self, customScript, configurationAttributes): + + print "Casa. init called" + self.authenticators = {} + self.uid_attr = self.getLocalPrimaryKey() + self.agamaFQN = "io.jans.casa.acctlinking.Launcher" + + custScriptService = CdiUtil.bean(CustomScriptService) + self.scriptsList = custScriptService.findCustomScripts(Collections.singletonList(CustomScriptType.PERSON_AUTHENTICATION), "jansConfProperty", "displayName", "jansEnabled", "jansLevel") + dynamicMethods = self.computeMethods(self.scriptsList) + + if len(dynamicMethods) > 0: + print "Casa. init. Loading scripts for dynamic modules: %s" % dynamicMethods + + for acr in dynamicMethods: + moduleName = self.modulePrefix + acr + try: + external = __import__(moduleName, globals(), locals(), ["PersonAuthentication"], -1) + module = external.PersonAuthentication(self.currentTimeMillis) + + print "Casa. init. Got dynamic module for acr %s" % acr + configAttrs = self.getConfigurationAttributes(acr, self.scriptsList) + + if acr == self.ACR_SG: + application_id = configurationAttributes.get("supergluu_app_id").getValue2() + configAttrs.put("application_id", SimpleCustomProperty("application_id", application_id)) + + if module.init(None, configAttrs): + module.configAttrs = configAttrs + self.authenticators[acr] = module + else: + print "Casa. init. Call to init in module '%s' returned False" % moduleName + except: + print "Casa. init. Failed to load module %s" % moduleName + print "Exception: ", sys.exc_info()[1] + + mobile_methods = configurationAttributes.get("mobile_methods") + self.mobile_methods = [] if mobile_methods == None else StringHelper.split(mobile_methods.getValue2(), ",") + + print "Casa. init. Initialized successfully" + return True + + + def destroy(self, configurationAttributes): + print "Casa. Destroyed called" + return True + + + def getApiVersion(self): + return 11 + + + def getAuthenticationMethodClaims(self, configurationAttributes): + return None + + + def isValidAuthenticationMethod(self, usageType, configurationAttributes): + print "Casa. isValidAuthenticationMethod called" + return True + + + def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): + return None + + + def authenticate(self, configurationAttributes, requestParameters, step): + print "Casa. authenticate for step %s" % str(step) + + userService = CdiUtil.bean(UserService) + authenticationService = CdiUtil.bean(AuthenticationService) + identity = CdiUtil.bean(Identity) + + if step == 1: + # Determine if external provider must be used + provider = ServerUtil.getFirstValue(requestParameters, "loginForm:provider") + if StringHelper.isNotEmpty(provider): + url = self.getAuthzRequestUrl(provider) + if url != None: + CdiUtil.bean(FacesService).redirectToExternalURL(url) + return url != None + + credentials = identity.getCredentials() + user_name = credentials.getUsername() + user_password = credentials.getPassword() + + if StringHelper.isNotEmptyString(user_name) and StringHelper.isNotEmptyString(user_password): + + foundUser = userService.getUserByAttribute(self.uid_attr, user_name) + #foundUser = userService.getUser(user_name) + if foundUser == None: + print "Casa. authenticate for step 1. Unknown username" + else: + platform_data = self.parsePlatformData(requestParameters) + preferred = foundUser.getAttribute("jansPreferredMethod") + mfaOff = preferred == None + logged_in = False + + if mfaOff: + logged_in = authenticationService.authenticate(user_name, user_password) + else: + acr = self.getSuitableAcr(foundUser, platform_data, preferred) + if acr != None: + module = self.authenticators[acr] + logged_in = module.authenticate(module.configAttrs, requestParameters, step) + + if logged_in: + foundUser = authenticationService.getAuthenticatedUser() + + if foundUser == None: + print "Casa. authenticate for step 1. Cannot retrieve logged user" + else: + if mfaOff: + identity.setWorkingParameter("skip2FA", True) + else: + #Determine whether to skip 2FA based on policy defined (global or user custom) + skip2FA = self.determineSkip2FA(userService, identity, foundUser, platform_data) + identity.setWorkingParameter("skip2FA", skip2FA) + identity.setWorkingParameter("ACR", acr) + + return True + + else: + print "Casa. authenticate for step 1 was not successful" + return False + + else: + user = authenticationService.getAuthenticatedUser() + if user == None: + print "Casa. authenticate for step 2. Cannot retrieve logged user" + return False + + #see casa.xhtml + alter = ServerUtil.getFirstValue(requestParameters, "alternativeMethod") + if alter != None: + #bypass the rest of this step if an alternative method was provided. Current step will be retried (see getNextStep) + self.simulateFirstStep(requestParameters, alter) + return True + + session_attributes = identity.getSessionId().getSessionAttributes() + acr = session_attributes.get("ACR") + #this working parameter is used in casa.xhtml + identity.setWorkingParameter("methods", ArrayList(self.getAvailMethodsUser(user, acr))) + + success = False + if acr in self.authenticators: + module = self.authenticators[acr] + success = module.authenticate(module.configAttrs, requestParameters, step) + + #Update the list of trusted devices if 2fa passed + if success: + print "Casa. authenticate. 2FA authentication was successful" + tdi = session_attributes.get("trustedDevicesInfo") + if tdi == None: + print "Casa. authenticate. List of user's trusted devices was not updated" + else: + user.setAttribute("jansTrustedDevices", tdi) + userService.updateUser(user) + else: + print "Casa. authenticate. 2FA authentication failed" + + return success + + return False + + + def prepareForStep(self, configurationAttributes, requestParameters, step): + print "Casa. prepareForStep %s" % str(step) + identity = CdiUtil.bean(Identity) + + if step == 1: + self.prepareUIParams(identity) + self.registeredProviders = self.parseProviderConfigs() + identity.setWorkingParameter("externalProviders", json.dumps(self.registeredProviders)) + return True + else: + session_attributes = identity.getSessionId().getSessionAttributes() + + authenticationService = CdiUtil.bean(AuthenticationService) + user = authenticationService.getAuthenticatedUser() + + if user == None: + print "Casa. prepareForStep. Cannot retrieve logged user" + return False + + acr = session_attributes.get("ACR") + print "Casa. prepareForStep. ACR = %s" % acr + identity.setWorkingParameter("methods", ArrayList(self.getAvailMethodsUser(user, acr))) + + if acr in self.authenticators: + module = self.authenticators[acr] + return module.prepareForStep(module.configAttrs, requestParameters, step) + else: + return False + + + def getExtraParametersForStep(self, configurationAttributes, step): + print "Casa. getExtraParametersForStep %s" % str(step) + list = ArrayList() + + if step > 1: + acr = CdiUtil.bean(Identity).getWorkingParameter("ACR") + + if acr in self.authenticators: + module = self.authenticators[acr] + params = module.getExtraParametersForStep(module.configAttrs, step) + if params != None: + list.addAll(params) + + list.addAll(Arrays.asList("ACR", "methods", "trustedDevicesInfo")) + else: + list.add("externalProviders") + + list.addAll(Arrays.asList("casa_contextPath", "casa_prefix", "casa_faviconUrl", "casa_extraCss", "casa_logoUrl")) + print "extras are %s" % list + return list + + + def getCountAuthenticationSteps(self, configurationAttributes): + print "Casa. getCountAuthenticationSteps called" + + if CdiUtil.bean(Identity).getWorkingParameter("skip2FA"): + return 1 + + acr = CdiUtil.bean(Identity).getWorkingParameter("ACR") + if acr in self.authenticators: + module = self.authenticators[acr] + return module.getCountAuthenticationSteps(module.configAttrs) + else: + return 2 + + print "Casa. getCountAuthenticationSteps. Could not determine the step count for acr %s" % acr + + + def getPageForStep(self, configurationAttributes, step): + print "Casa. getPageForStep called %s" % str(step) + + if step > 1: + acr = CdiUtil.bean(Identity).getWorkingParameter("ACR") + if acr in self.authenticators: + module = self.authenticators[acr] + page = module.getPageForStep(module.configAttrs, step) + else: + page=None + + return page + + return "/casa/login.xhtml" + + + def getNextStep(self, configurationAttributes, requestParameters, step): + + print "Casa. getNextStep called %s" % str(step) + if step > 1: + acr = ServerUtil.getFirstValue(requestParameters, "alternativeMethod") + if acr != None: + print "Casa. getNextStep. Use alternative method %s" % acr + CdiUtil.bean(Identity).setWorkingParameter("ACR", acr) + #retry step with different acr + return 2 + + return -1 + + + def logout(self, configurationAttributes, requestParameters): + print "Casa. logout called" + return True + +# Miscelaneous + + def getLocalPrimaryKey(self): + entryManager = CdiUtil.bean(PersistenceEntryManager) + config = GluuConfiguration() + config = entryManager.find(config.getClass(), "ou=configuration,o=jans") + #Pick (one) attribute where user id is stored (e.g. uid/mail) + # primaryKey is the primary key on the backend AD / LDAP Server + # localPrimaryKey is the primary key on Gluu. This attr value has been mapped with the primary key attr of the backend AD / LDAP when configuring cache refresh + uid_attr = config.getIdpAuthn().get(0).getConfig().findValue("localPrimaryKey").asText() + print "Casa. init. uid attribute is '%s'" % uid_attr + return uid_attr + + + def getSettings(self): + entryManager = CdiUtil.bean(PersistenceEntryManager) + config = ApplicationConfiguration() + config = entryManager.find(config.getClass(), "ou=casa,ou=configuration,o=jans") + settings = config.getSettings() + + if settings == None: + print "Casa. getSettings. Failed to parse casa settings from DB" + return settings + + + def computeMethods(self, scriptList): + + methods = [] + mapping = {} + cmConfigs = self.getSettings() + + if cmConfigs != None and cmConfigs.getAcrPluginMap() != None: + mapping = cmConfigs.getAcrPluginMap().keySet() + + for m in mapping: + for customScript in scriptList: + if customScript.getName() == m and customScript.isEnabled(): + methods.append(m) + + print "Casa. computeMethods. %s" % methods + return methods + + + def getConfigurationAttributes(self, acr, scriptsList): + + configMap = HashMap() + for customScript in scriptsList: + if customScript.getName() == acr and customScript.isEnabled(): + for prop in customScript.getConfigurationProperties(): + configMap.put(prop.getValue1(), SimpleCustomProperty(prop.getValue1(), prop.getValue2())) + + print "Casa. getConfigurationAttributes. %d configuration properties were found for %s" % (configMap.size(), acr) + return configMap + + + def getAvailMethodsUser(self, user, skip=None): + methods = HashSet() + + for method in self.authenticators: + try: + module = self.authenticators[method] + if module.hasEnrollments(module.configAttrs, user): + methods.add(method) + except: + print "Casa. getAvailMethodsUser. hasEnrollments call could not be issued for %s module" % method + print "Exception: ", sys.exc_info()[1] + + try: + if skip != None: + # skip is guaranteed to be a member of methods (if hasEnrollments routines are properly implemented). + # A call to remove strangely crashes when skip is absent + methods.remove(skip) + except: + print "Casa. getAvailMethodsUser. methods list does not contain %s" % skip + + print "Casa. getAvailMethodsUser %s" % methods.toString() + return methods + + + def prepareUIParams(self, identity): + + print "Casa. prepareUIParams. Reading UI branding params" + cacheService = CdiUtil.bean(CacheService) + casaAssets = cacheService.get("casa_assets") + + if casaAssets == None: + #This may happen when cache type is IN_MEMORY, where actual cache is merely a local variable + #(a expiring map) living inside Casa webapp, not oxAuth webapp + + sets = self.getSettings() + + custPrefix = "/custom" + logoUrl = "/images/logo.png" + faviconUrl = "/images/favicon.ico" + if (sets.getExtraCssSnippet() != None) or sets.isUseExternalBranding(): + logoUrl = custPrefix + logoUrl + faviconUrl = custPrefix + faviconUrl + + prefix = custPrefix if sets.isUseExternalBranding() else "" + + casaAssets = { + "contextPath": "/jans-casa", + "prefix" : prefix, + "faviconUrl" : faviconUrl, + "extraCss": sets.getExtraCssSnippet(), + "logoUrl": logoUrl + } + + #Setting a single variable with the whole map does not work... + identity.setWorkingParameter("casa_contextPath", casaAssets['contextPath']) + identity.setWorkingParameter("casa_prefix", casaAssets['prefix']) + identity.setWorkingParameter("casa_faviconUrl", casaAssets['contextPath'] + casaAssets['faviconUrl']) + identity.setWorkingParameter("casa_extraCss", casaAssets['extraCss']) + identity.setWorkingParameter("casa_logoUrl", casaAssets['contextPath'] + casaAssets['logoUrl']) + + + def simulateFirstStep(self, requestParameters, acr): + #To simulate 1st step, there is no need to call: + # getPageforstep (no need as user/pwd won't be shown again) + # isValidAuthenticationMethod (by restriction, it returns True) + # prepareForStep (by restriction, it returns True) + # getExtraParametersForStep (by restriction, it returns None) + print "Casa. simulateFirstStep. Calling authenticate (step 1) for %s module" % acr + if acr in self.authenticators: + module = self.authenticators[acr] + auth = module.authenticate(module.configAttrs, requestParameters, 1) + print "Casa. simulateFirstStep. returned value was %s" % auth + + +# 2FA policy enforcement + + def parsePlatformData(self, requestParameters): + try: + #Find device info passed in HTTP request params (see index.xhtml) + platform = ServerUtil.getFirstValue(requestParameters, "loginForm:platform") + deviceInf = json.loads(platform) + except: + print "Casa. parsePlatformData. Error parsing platform data" + deviceInf = None + + return deviceInf + + + def getSuitableAcr(self, user, deviceInf, preferred): + + onMobile = deviceInf != None and 'isMobile' in deviceInf and deviceInf['isMobile'] + id = user.getUserId() + strongest = -1 + acr = None + user_methods = self.getAvailMethodsUser(user) + + for s in self.scriptsList: + name = s.getName() + level = Integer.MAX_VALUE if name == preferred else s.getLevel() + if user_methods.contains(name) and level > strongest and (not onMobile or name in self.mobile_methods): + acr = name + strongest = level + + print "Casa. getSuitableAcr. On mobile = %s" % onMobile + if acr == None and onMobile: + print "Casa. getSuitableAcr. No mobile-friendly authentication method available for user %s" % id + # user_methods is not empty when this function is called, so just pick any + acr = user_methods.stream().findFirst().get() + + print "Casa. getSuitableAcr. %s was selected for user %s" % (acr, id) + return acr + + + def determineSkip2FA(self, userService, identity, foundUser, deviceInf): + + cmConfigs = self.getSettings() + + if cmConfigs == None: + print "Casa. determineSkip2FA. Failed to read policy_2fa" + return False + + cmConfigs = cmConfigs.getPluginSettings().get('strong-authn-settings') + + policy2FA = 'EVERY_LOGIN' + if cmConfigs != None and cmConfigs.get('policy_2fa') != None: + policy2FA = ','.join(cmConfigs.get('policy_2fa')) + + print "Casa. determineSkip2FA with general policy %s" % policy2FA + policy2FA += ',' + skip2FA = False + + if 'CUSTOM,' in policy2FA: + #read setting from user profile + policy = foundUser.getAttribute("jansStrongAuthPolicy") + if policy == None: + policy = 'EVERY_LOGIN,' + else: + policy = policy.upper() + ',' + print "Casa. determineSkip2FA. Using user's enforcement policy %s" % policy + + else: + #If it's not custom, then apply the global setting admin defined + policy = policy2FA + + if not 'EVERY_LOGIN,' in policy: + locationCriterion = 'LOCATION_UNKNOWN,' in policy + deviceCriterion = 'DEVICE_UNKNOWN,' in policy + + if locationCriterion or deviceCriterion: + if deviceInf == None: + print "Casa. determineSkip2FA. No user device data. Forcing 2FA to take place..." + else: + skip2FA = self.process2FAPolicy(identity, foundUser, deviceInf, locationCriterion, deviceCriterion) + + if skip2FA: + print "Casa. determineSkip2FA. Second factor is skipped" + #Update attribute if authentication will not have second step + devInf = identity.getWorkingParameter("trustedDevicesInfo") + if devInf != None: + foundUser.setAttribute("jansTrustedDevices", devInf) + userService.updateUser(foundUser) + else: + print "Casa. determineSkip2FA. Unknown %s policy: cannot skip 2FA" % policy + + return skip2FA + + + def process2FAPolicy(self, identity, foundUser, deviceInf, locationCriterion, deviceCriterion): + + skip2FA = False + #Retrieve user's devices info + devicesInfo = foundUser.getAttribute("jansTrustedDevices") + + #do geolocation + geodata = self.getGeolocation(identity) + if geodata == None: + print "Casa. process2FAPolicy: Geolocation data not obtained. 2FA skipping based on location cannot take place" + + try: + encService = CdiUtil.bean(EncryptionService) + + if devicesInfo == None: + print "Casa. process2FAPolicy: There are no trusted devices for user yet" + #Simulate empty list + devicesInfo = "[]" + else: + devicesInfo = encService.decrypt(devicesInfo) + + devicesInfo = json.loads(devicesInfo) + + partialMatch = False + idx = 0 + #Try to find a match for device only + for device in devicesInfo: + partialMatch = device['browser']['name']==deviceInf['name'] and device['os']['version']==deviceInf['os']['version'] and device['os']['family']==deviceInf['os']['family'] + if partialMatch: + break + idx+=1 + + matchFound = False + + #At least one of locationCriterion or deviceCriterion is True + if locationCriterion and not deviceCriterion: + #this check makes sense if there is city data only + if geodata!=None: + for device in devicesInfo: + #Search all registered cities that are found in trusted devices + for origin in device['origins']: + matchFound = matchFound or origin['city']==geodata['city'] + + elif partialMatch: + #In this branch deviceCriterion is True + if not locationCriterion: + matchFound = True + elif geodata!=None: + for origin in devicesInfo[idx]['origins']: + matchFound = matchFound or origin['city']==geodata['city'] + + skip2FA = matchFound + now = Date().getTime() + + #Update attribute oxTrustedDevicesInfo accordingly + if partialMatch: + #Update an existing record (update timestamp in city, or else add it) + if geodata != None: + partialMatch = False + idxCity = 0 + + for origin in devicesInfo[idx]['origins']: + partialMatch = origin['city']==geodata['city'] + if partialMatch: + break; + idxCity+=1 + + if partialMatch: + devicesInfo[idx]['origins'][idxCity]['timestamp'] = now + else: + devicesInfo[idx]['origins'].append({"city": geodata['city'], "country": geodata['country'], "timestamp": now}) + else: + #Create a new entry + browser = {"name": deviceInf['name'], "version": deviceInf['version']} + os = {"family": deviceInf['os']['family'], "version": deviceInf['os']['version']} + + if geodata == None: + origins = [] + else: + origins = [{"city": geodata['city'], "country": geodata['country'], "timestamp": now}] + + obj = {"browser": browser, "os": os, "addedOn": now, "origins": origins} + devicesInfo.append(obj) + + enc = json.dumps(devicesInfo, separators=(',',':')) + enc = encService.encrypt(enc) + identity.setWorkingParameter("trustedDevicesInfo", enc) + + except: + print "Casa. process2FAPolicy. Error!", sys.exc_info()[1] + + return skip2FA + + + def getGeolocation(self, identity): + + session_attributes = identity.getSessionId().getSessionAttributes() + if session_attributes.containsKey("remote_ip"): + remote_ip = session_attributes.get("remote_ip").split(",", 2)[0].strip() + if StringHelper.isNotEmpty(remote_ip): + + httpService = CdiUtil.bean(HttpService) + + http_client = httpService.getHttpsClient() + http_client_params = http_client.getParams() + http_client_params.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 4 * 1000) + + geolocation_service_url = "http://ip-api.com/json/%s?fields=country,city,status,message" % remote_ip + geolocation_service_headers = { "Accept" : "application/json" } + + try: + http_service_response = httpService.executeGet(http_client, geolocation_service_url, geolocation_service_headers) + http_response = http_service_response.getHttpResponse() + except: + print "Casa. Determine remote location. Exception: ", sys.exc_info()[1] + return None + + try: + if not httpService.isResponseStastusCodeOk(http_response): + print "Casa. Determine remote location. Get non 200 OK response from server:", str(http_response.getStatusLine().getStatusCode()) + httpService.consume(http_response) + return None + + response_bytes = httpService.getResponseContent(http_response) + response_string = httpService.convertEntityToString(response_bytes, Charset.forName("UTF-8")) + httpService.consume(http_response) + finally: + http_service_response.closeConnection() + + if response_string == None: + print "Casa. Determine remote location. Get empty response from location server" + return None + + response = json.loads(response_string) + + if not StringHelper.equalsIgnoreCase(response['status'], "success"): + print "Casa. Determine remote location. Get response with status: '%s'" % response['status'] + return None + + return response + + return None + + + def getLogoutExternalUrl(self, configurationAttributes, requestParameters): + print "Get external logout URL call" + return None + +# External authentication providers integration + + def getAuthzRequestUrl(self, providerId): + + url = None + if providerId in self.registeredProviders: + + print "Casa. getAuthzRequestUrl. Building an authz request URL for agama" + + params = ["response_type", "client_id", "scope", "redirect_uri", "state"] + attrs = CdiUtil.bean(Identity).getSessionId().getSessionAttributes() + + authzParams = {} + # use passport-* instead of casa + authzParams["acr_values"] = "agama" + + # set the provider to use + flowParams = URLEncoder.encode(json.dumps({ "providerId" : providerId })) + authzParams["agama_flow"] = self.agamaFQN + "-" + flowParams + + # avoids flow updating the profile of user if he has been provisioned previously + authzParams["skipProfileUpdate"] = "true" + + # copy the params in the current casa request + for param in params: + authzParams[param] = URLEncoder.encode(attrs.get(param), "UTF-8") + + url = "/jans-auth/restv1/authorize?" + for param in authzParams: + url += "&" + param + "=" + authzParams[param] + + else: + print "Casa. getAuthzRequestUrl. Provider %s not recognized" % providerId + + return url + + + def parseProviderConfigs(self): + + providers = {} + try: + entryManager = CdiUtil.bean(PersistenceEntryManager) + dn = "agFlowQName=%s,ou=flows,ou=agama,o=jans" % self.agamaFQN + conf = entryManager.find(Flow().getClass(), dn).getMetadata().getProperties() + + if conf == None: + return providers + + prop = "enabled" + for provId in conf: + pr = conf.get(provId) + if not pr.containsKey(prop) or pr.get(prop): + providers[provId] = { "displayName": pr.get("displayName"), "logoImg": pr.get("logoImg") } + + return providers + except: + print "Casa. parseProviderConfigs. An error occurred while building the list of supported authentication providers", sys.exc_info()[1] + + return providers diff --git a/jans-casa/plugins/acct-linking/extras/agama/code/io.jans.casa.acctlinking.Launcher.flow b/jans-casa/plugins/acct-linking/extras/agama/code/io.jans.casa.acctlinking.Launcher.flow new file mode 100644 index 00000000000..d6938e5e62e --- /dev/null +++ b/jans-casa/plugins/acct-linking/extras/agama/code/io.jans.casa.acctlinking.Launcher.flow @@ -0,0 +1,65 @@ +Flow io.jans.casa.acctlinking.Launcher + Basepath "" + Configs providers + Inputs providerId uidRef + +provider = providers.$providerId +//See class io.jans.inbound.Provider for reference + +When provider is null or provider.enabled is false + msg = Call java.lang.String#format "Provider '%s' not recognized. Is it enabled?" providerId + obj = { success: false, error: msg } + Finish obj + +//Launch matching flow and retrieve profile +Log "Initiating external authentication for identity provider '%'" providerId +obj = Trigger $provider.flowQname provider + +When obj.success is false + Finish obj + +field = Call io.jans.inbound.Utils#getMappingField provider.mappingClassField +idProc = Call io.jans.inbound.IdentityProcessor#new provider +profile = Call idProc applyMapping obj.data field + +field = null +//In profile, every key is associated to a list +Log "@d Mapped profile is\n" profile + +When profile.ID is null or profile.ID.empty is true + obj = { success: false, error: "Mapped profile misses value for 'ID'" } + Finish obj + +When profile.mail is null or profile.mail.empty is true + Log "Incoming user has no e-mail value" + + //Prompt for e-mail if necessary + When provider.requestForEmail is true + obj = RRF "email-prompt.ftlh" + mail = obj.email + + When mail is null + obj = { success: false, error: "Unable to complete profile data: e-mail not provided" } + Finish obj + + profile.mail = [ mail ] + +jansExtUid = Call io.jans.casa.acctlinking.UidUtils#computeExtUid providerId profile.ID[0] +uid = null + +When profile.uid is not null + uid = profile.uid[0] + +uid = Call io.jans.casa.acctlinking.UidUtils#lookupUid uidRef uid profile.ID[0] "jansExtUid" jansExtUid +profile.jansExtUid = Call io.jans.casa.acctlinking.UidUtils#attrValuesAdding uid "jansExtUid" jansExtUid + +profile.uid = [ uid ] +profile.ID = null //ID not part of DB schema - jansExtUid has what is needed + +uid | E = Call idProc process profile +When E is null + Finish uid + +Log "@e Unable to process the incoming user" E +obj = { success: false, error: E.message } +Finish obj diff --git a/jans-casa/plugins/acct-linking/extras/agama/lib/io/jans/casa/acctlinking/Mappings.java b/jans-casa/plugins/acct-linking/extras/agama/lib/io/jans/casa/acctlinking/Mappings.java new file mode 100644 index 00000000000..bc72da34944 --- /dev/null +++ b/jans-casa/plugins/acct-linking/extras/agama/lib/io/jans/casa/acctlinking/Mappings.java @@ -0,0 +1,71 @@ +package io.jans.casa.acctlinking; + +import java.util.function.UnaryOperator; +import java.util.HashMap; +import java.util.Map; + +/** + * Fields of this class can be referenced in the config properties of flow + * io.jans.casa.acctlinking.Launcher + */ +public final class Mappings { + + public static final UnaryOperator> GOOGLE = + + profile -> { + Map map = new HashMap<>(); + + map.put("ID", profile.get("sub")); + map.put("mail", profile.get("email")); + map.put("cn", profile.get("name")); + map.put("sn", profile.get("family_name")); + map.put("displayName", profile.get("given_name")); + map.put("givenName", profile.get("given_name")); + + return map; + }; + + //See https://developers.facebook.com/docs/graph-api/reference/user + public static final UnaryOperator> FACEBOOK = + + profile -> { + Map map = new HashMap<>(); + + map.put("ID", profile.get("id")); + map.put("mail", profile.get("email")); + map.put("cn", profile.get("name")); + map.put("sn", profile.get("last_name")); + map.put("displayName", profile.get("first_name")); + map.put("givenName", profile.get("first_name")); + + return map; + }; + + public static final UnaryOperator> APPLE = + + profile -> { + Map map = new HashMap<>(); + + map.put("ID", profile.get("sub")); + map.put("mail", profile.get("email")); + + return map; + }; + + //See https://docs.github.com/en/rest/users/users + public static final UnaryOperator> GITHUB = + + profile -> { + Map map = new HashMap<>(); + + map.put("ID", profile.getOrDefault("login", profile.get("id"))); + map.put("mail", profile.get("email")); + map.put("displayName", profile.get("name")); + map.put("givenName", profile.get("name")); + + return map; + }; + + private Mappings() { } + +} diff --git a/jans-casa/plugins/acct-linking/extras/agama/lib/io/jans/casa/acctlinking/UidUtils.java b/jans-casa/plugins/acct-linking/extras/agama/lib/io/jans/casa/acctlinking/UidUtils.java new file mode 100644 index 00000000000..53043e10d6f --- /dev/null +++ b/jans-casa/plugins/acct-linking/extras/agama/lib/io/jans/casa/acctlinking/UidUtils.java @@ -0,0 +1,83 @@ +package io.jans.casa.acctlinking; + +import io.jans.as.common.model.common.User; +import io.jans.as.common.service.common.UserService; +import io.jans.service.cache.CacheProvider; +import io.jans.service.cdi.util.CdiUtil; + +import java.io.IOException; +import java.util.*; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class UidUtils { + + private static final Logger logger = LoggerFactory.getLogger(Utils.class); + + public static String lookupUid(String uidRef, String uid, String extUid, String jansExtAttrName, + String jansExtUid) throws IOException { + + if (uidRef == null) { + boolean uidPassed = uid != null; + + if (uidPassed) { + logger.debug("Using uid passed: {}", uid); + return uid; + } + + //Find if the external account is already linked to a local one + User user = CdiUtil.bean(UserService.class).getUserByAttribute(jansExtAttrName, jansExtUid, true); + if (user == null) { + logger.info("Building a uid based on external id {}", extUid); + return extUid + "-" + randSuffix(3); + } + logger.info("Using uid of the account already linked to {}", extUid); + return user.getUserId(); + } + + logger.debug("Looking up uid ref {}", uidRef); + Object value = CdiUtil.bean(CacheProvider.class).get(uidRef); + if (value == null) throw new IOException("uid reference passed not found in Cache!"); + + return value.toString(); + + } + + public static List attrValuesAdding(String uid, String attributeName, String valueToAdd) { + + User user = CdiUtil.bean(UserService.class).getUserByAttribute("uid", uid, false); + if (user == null) return Collections.singletonList(valueToAdd); + + List values = new ArrayList<>(); + List currentValues = Optional.ofNullable(user.getAttributeValues(attributeName)) + .orElse(Collections.emptyList()); + values.addAll(currentValues); + + if (!currentValues.contains(valueToAdd)) { + values.add(valueToAdd); + } + return values; + + } + + public static String computeExtUid(String providerId, String id) { + return providerId + ":" + id; + } + + private Utils() { } + + // The idea here is to generate a random 3-char lengthed string "easy to remember" + private static String randSuffix(int randSuffixLen) { + + String s = ""; + int radix = Math.min(15, Character.MAX_RADIX); //radix 15 entails characters: 0-9 plus a-e + + for (int i = 0; i < randSuffixLen; i++) { + long rnd = Math.random() * radix; // rnd will belong to [0, radix - 1] + s += Integer.toString((int) rnd, radix); // this adds a single character to s + } + return s; + } + +} diff --git a/jans-casa/plugins/acct-linking/extras/agama/project.json b/jans-casa/plugins/acct-linking/extras/agama/project.json new file mode 100644 index 00000000000..2c5533497c6 --- /dev/null +++ b/jans-casa/plugins/acct-linking/extras/agama/project.json @@ -0,0 +1,58 @@ +{ + "projectName": "casa-account-linking", + "author": "jgomer2001", + "type": "Community", + "version": "1.0.0", + "description": "A helper project for Jans Casa accounts linking plugin", + "noDirectLaunch": [ ], + "configs": { + "io.jans.casa.acctlinking.Launcher": { + + "facebook": { + "flowQname": "io.jans.inbound.GenericProvider", + "displayName": "Facebook", + "mappingClassField": "io.jans.casa.acctlinking.Mappings.FACEBOOK", + "logoImg": "facebook.png", + "oauthParams": { + "authzEndpoint": "https://www.facebook.com/v14.0/dialog/oauth", + "tokenEndpoint": "https://graph.facebook.com/v14.0/oauth/access_token", + "userInfoEndpoint": "https://graph.facebook.com/v14.0/me", + "clientId": "", + "clientSecret": "", + "scopes": ["email", "public_profile"] + } + }, + + "github": { + "flowQname": "io.jans.inbound.GenericProvider", + "displayName": "Github", + "mappingClassField": "io.jans.casa.acctlinking.Mappings.GITHUB", + "oauthParams": { + "authzEndpoint": "https://github.com/login/oauth/authorize", + "tokenEndpoint": "https://github.com/login/oauth/access_token", + "userInfoEndpoint": "https://api.github.com/user", + "clientId": "", + "clientSecret": "", + "scopes": ["user"] + } + }, + + "google": { + "flowQname": "io.jans.inbound.GenericProvider", + "displayName": "Google", + "mappingClassField": "io.jans.casa.acctlinking.Mappings.GOOGLE", + "enabled": false, + "skipProfileUpdate": true, + "oauthParams": { + "authzEndpoint": "https://accounts.google.com/o/oauth2/v2/auth", + "tokenEndpoint": "https://oauth2.googleapis.com/token", + "userInfoEndpoint": "https://www.googleapis.com/oauth2/v3/userinfo", + "clientId": "", + "clientSecret": "", + "scopes": ["email", "profile"] + } + } + + } + } +} diff --git a/jans-casa/plugins/acct-linking/extras/agama/web/apple.png b/jans-casa/plugins/acct-linking/extras/agama/web/apple.png new file mode 100644 index 0000000000000000000000000000000000000000..d852c10925f8f59f5bb1579c832554099b2d68a4 GIT binary patch literal 8171 zcmV004&%004{+008|`004nN004b?008NW002DY000@xb3BE2000Uv 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 + + + + + + + + + +
+
+ +
+ +
+ +
+

Please provide an e-mail address to proceed

+ +
+
+ +
+ +
+
+
+
+ +
+
+
+
+ +
+ +
+
+
+
+ + + diff --git a/jans-casa/plugins/acct-linking/extras/agama/web/facebook.png b/jans-casa/plugins/acct-linking/extras/agama/web/facebook.png new file mode 100644 index 0000000000000000000000000000000000000000..6f2d7a0f1eb0511012e8114ee9805eb67db29f7d GIT binary patch literal 4822 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

NnlU$0zi`cjMZF>+M!v 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 literal 0 HcmV?d00001 diff --git a/jans-casa/plugins/acct-linking/extras/agama/web/google.png b/jans-casa/plugins/acct-linking/extras/agama/web/google.png new file mode 100644 index 0000000000000000000000000000000000000000..f92017b3bf7fe2e92e12bf5bb0bc2727a5377a7c GIT binary patch literal 105019 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%0AZ}-GYb$jpA*3`1mxFq_^EkDf458_ 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 LE2Fm<*T??_>S|f?5t2wl%JNFlghxL zF>&sMjb4WXMB4U;TvQTeIqE25RHAE=}D76A5FHuJaY5s&X=pV6tfmt3Wywq{_b)dmTZypT2^R7a zPWqZQYvm5XsYOK=0=%xfe4X!w&3&$ws?y)N$LEmjN*iCfXZ8E9+nsymn_WDQ-8Epl zSjgIs68Gd2ueN_pkJy=aBI|!$^kJX<^L{>;-p`=a7SP0GR*?VbHUgGKN%KnT)fJaSXE| + + + + + + #{msgs['casa.login.title']} + + +

#{msgs['passport.javascriptRequired']}

+ + +
+

#{msgs['casa.login.panel_title']}

+ + +
+ + +
+
+ + +
+
+ +

OR use an external service to sign in:

+
+
+ + + +
+
+ + +
+

+ Correlation Id: +

+
+ + +
+
+ + + + From 145dae1042c83094e4e37848322a0689cc3b41d5 Mon Sep 17 00:00:00 2001 From: jgomer2001 Date: Mon, 18 Mar 2024 11:46:51 -0500 Subject: [PATCH 2/4] feat: add acct linking plugin #7556 --- .../jans/casa/core/PasswordStatusService.java | 2 +- jans-casa/plugins/acct-linking/pom.xml | 109 ++++++++++ .../acctlinking/AccountsLinkingPlugin.java | 24 +++ .../acctlinking/AccountsLinkingService.java | 196 ++++++++++++++++++ .../acctlinking/extension/AdminMenu.java | 22 ++ .../acctlinking/extension/UserMenu.java | 23 ++ .../vm/AccountsLinkingSettingsVM.java | 42 ++++ .../acctlinking/vm/AccountsLinkingVM.java | 143 +++++++++++++ .../acctlinking/vm/SiteRedirectVM.java | 179 ++++++++++++++++ .../resources/assets/admin/al-settings.zul | 59 ++++++ .../src/main/resources/assets/admin/menu.zul | 10 + .../src/main/resources/assets/user/index.zul | 79 +++++++ .../main/resources/assets/user/interlude.zul | 17 ++ .../src/main/resources/assets/user/menu.zul | 10 + .../main/resources/labels/zk-label.properties | 56 +++++ jans-casa/pom.xml | 1 + 16 files changed, 971 insertions(+), 1 deletion(-) create mode 100644 jans-casa/plugins/acct-linking/pom.xml create mode 100644 jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/AccountsLinkingPlugin.java create mode 100644 jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/AccountsLinkingService.java create mode 100644 jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/extension/AdminMenu.java create mode 100644 jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/extension/UserMenu.java create mode 100644 jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/vm/AccountsLinkingSettingsVM.java create mode 100644 jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/vm/AccountsLinkingVM.java create mode 100644 jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/vm/SiteRedirectVM.java create mode 100644 jans-casa/plugins/acct-linking/src/main/resources/assets/admin/al-settings.zul create mode 100644 jans-casa/plugins/acct-linking/src/main/resources/assets/admin/menu.zul create mode 100644 jans-casa/plugins/acct-linking/src/main/resources/assets/user/index.zul create mode 100644 jans-casa/plugins/acct-linking/src/main/resources/assets/user/interlude.zul create mode 100644 jans-casa/plugins/acct-linking/src/main/resources/assets/user/menu.zul create mode 100644 jans-casa/plugins/acct-linking/src/main/resources/labels/zk-label.properties diff --git a/jans-casa/app/src/main/java/io/jans/casa/core/PasswordStatusService.java b/jans-casa/app/src/main/java/io/jans/casa/core/PasswordStatusService.java index c17813c25aa..9ca7e9c5293 100644 --- a/jans-casa/app/src/main/java/io/jans/casa/core/PasswordStatusService.java +++ b/jans-casa/app/src/main/java/io/jans/casa/core/PasswordStatusService.java @@ -39,8 +39,8 @@ public boolean isPassResetAvailable() { public void reloadStatus() { - passSetAvailable = false; //Setting user's password is a disabled feature in Jans Casa IdentityPerson p = persistenceService.get(IdentityPerson.class, persistenceService.getPersonDn(asco.getUser().getId())); + passSetAvailable = !p.hasPassword(); passResetAvailable = p.hasPassword() && confSettings.isEnablePassReset(); } diff --git a/jans-casa/plugins/acct-linking/pom.xml b/jans-casa/plugins/acct-linking/pom.xml new file mode 100644 index 00000000000..6c9ee66bad4 --- /dev/null +++ b/jans-casa/plugins/acct-linking/pom.xml @@ -0,0 +1,109 @@ + + + + 4.0.0 + + io.jans.casa.plugins + ${plugin.id} + 1.1.0-SNAPSHOT + jar + + + 11 + 11 + acct-linking + + + + + jans + Janssen project repository + https://maven.jans.io/maven + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 3.1.0 + + + jar-with-dependencies + + + + ${plugin.id} + ${project.version} + Janssen project + io.jans.casa.plugins.acctlinking.AccountsLinkingPlugin + + Allows the user to link their external identities (social sites and other OAuth providers) + to his local Jans account + + Available under Apache 2 license + io.jans.casa.plugins + + + + + + make-assembly + package + + single + + + + + + com.github.spotbugs + spotbugs-maven-plugin + 4.2.0 + + + + + + + + com.nimbusds + oauth2-oidc-sdk + 11.7 + provided + + + + io.jans + agama-inbound + ${project.version} + + + * + * + + + + + + io.jans + jans-core-cache + ${project.version} + provided + + + io.jans + casa-shared + ${project.version} + provided + + + io.jans + casa-config + ${project.version} + provided + + + + diff --git a/jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/AccountsLinkingPlugin.java b/jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/AccountsLinkingPlugin.java new file mode 100644 index 00000000000..4503d08178a --- /dev/null +++ b/jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/AccountsLinkingPlugin.java @@ -0,0 +1,24 @@ +package io.jans.casa.plugins.acctlinking; + +import org.pf4j.Plugin; +import org.pf4j.PluginWrapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AccountsLinkingPlugin extends Plugin { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + public AccountsLinkingPlugin(PluginWrapper wrapper) throws Exception { + super(wrapper); + } + + @Override + public void start() { + } + + @Override + public void delete() { + } + +} diff --git a/jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/AccountsLinkingService.java b/jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/AccountsLinkingService.java new file mode 100644 index 00000000000..d90fe3f8462 --- /dev/null +++ b/jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/AccountsLinkingService.java @@ -0,0 +1,196 @@ +package io.jans.casa.plugins.acctlinking; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.type.TypeReference; +import com.nimbusds.oauth2.sdk.http.HTTPRequest; +import com.nimbusds.oauth2.sdk.http.HTTPResponse; +import com.nimbusds.oauth2.sdk.ParseException; + +import io.jans.casa.conf.OIDCClientSettings; +import io.jans.casa.core.model.IdentityPerson; +import io.jans.casa.misc.Utils; +import io.jans.casa.model.ApplicationConfiguration; +import io.jans.casa.service.IPersistenceService; +import io.jans.inbound.Provider; + +import java.io.IOException; +import java.net.*; +import java.util.*; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static java.nio.charset.StandardCharsets.UTF_8; + +public class AccountsLinkingService { + + public static final String CASA_AGAMA_FLOW = "io.jans.casa.acctlinking.Launcher"; + + public static final String READ_SCOPE = "https://jans.io/oauth/config/agama.readonly"; + + private static final String AGAMA_PRJ = "casa-account-linking"; + + private static final String CONFIGS_ENDPOINT = + "/jans-config-api/api/v1/agama-deployment/configs/" + AGAMA_PRJ; + + private Logger logger = LoggerFactory.getLogger(getClass()); + + private static AccountsLinkingService instance; + private IPersistenceService ips; + private ObjectMapper mapper; + + private OIDCClientSettings clSettings; + private String issuer; + private String basicAuthnHeader; + + public static AccountsLinkingService getInstance() { + if (instance == null) { + instance = new AccountsLinkingService(); + } + return instance; + } + + public OIDCClientSettings getCasaClient() { + return clSettings; + } + + public Map getProviders(boolean enabledOnly) throws Exception { + + HTTPRequest request = new HTTPRequest(HTTPRequest.Method.GET, + new URL(issuer + CONFIGS_ENDPOINT)); + setTimeouts(request); + request.setAuthorization(basicAuthnHeader); + request.setAuthorization("Bearer " + getAToken()); + + HTTPResponse r = request.send(); + r.ensureStatusCode(200); + + Map> madam = mapper.readValue( + r.getBody(), new TypeReference>>(){}); + + Map madman = Optional.ofNullable(madam) + .map(m -> m.get(CASA_AGAMA_FLOW)).orElse(Collections.emptyMap()); + + if (enabledOnly) { + madman = madman.entrySet().stream().filter(e -> e.getValue().isEnabled()) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + } + return madman; + + } + + public Map getAccounts(String userId, Set knownProviders) { + + Map accts = new HashMap<>(); + for (String extUid : getPerson(userId).getJansExtUid()) { + //See method computeExtUid + int i = extUid.indexOf(":"); + + if (i > 0 && i < extUid.length() - 1) { + String pref = extUid.substring(0, i); + if (knownProviders.contains(pref)) { + accts.put(pref, extUid.substring(i + 1)); + } + } + } + return accts; + + } + + /* + //linking occurs at the Agama flow + public boolean link(String userId, String providerId, String extUid) { + + try { + IdentityPerson p = getPerson(userId); + List extUids = new ArrayList<>(p.getJansExtUid()); + extUids.add(computeExtUid(providerId, extUid)); + + p.setJansExtUid(extUids); + ips.modify(p); + return true; + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + return false; + + }*/ + + public boolean delink(String userId, String providerId, String extUid) { + + try { + IdentityPerson p = getPerson(userId); + List extUids = new ArrayList<>(p.getJansExtUid()); + extUids.remove(computeExtUid(providerId, extUid)); + + p.setJansExtUid(extUids); + ips.modify(p); + return true; + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + return false; + + } + + public boolean hasPassword(String id) { + return getPerson(id).hasPassword(); + } + + private IdentityPerson getPerson(String id) { + return ips.get(IdentityPerson.class, ips.getPersonDn(id)); + } + + private String computeExtUid(String providerId, String id) { + //This method HAS to match computeExtUid in class io.jans.agama.inbound.Utils + return providerId + ":" + id; + } + + private AccountsLinkingService() { + logger.info("Initializing AccountsLinkingService"); + mapper = new ObjectMapper(); + + ips = Utils.managedBean(IPersistenceService.class); + issuer = ips.getIssuerUrl(); + logger.debug("Issuer is {}", issuer); + + clSettings = ips.get(ApplicationConfiguration.class, "ou=casa,ou=configuration,o=jans") + .getSettings().getOidcSettings().getClient(); + + String authz = clSettings.getClientId() + ":" + clSettings.getClientSecret(); + authz = new String(Base64.getEncoder().encode(authz.getBytes(UTF_8)), UTF_8); + basicAuthnHeader = "Basic " + authz; + + } + + private String getAToken() throws IOException { + + StringJoiner joiner = new StringJoiner("&"); + Map.of("grant_type", "client_credentials", "scope", URLEncoder.encode(READ_SCOPE, UTF_8)) + .forEach((k, v) -> joiner.add(k + "=" + v)); + + logger.info("Calling token endpoint"); + + HTTPRequest request = new HTTPRequest( + HTTPRequest.Method.POST, new URL(issuer + "/jans-auth/restv1/token")); + setTimeouts(request); + request.setQuery(joiner.toString()); + request.setAuthorization(basicAuthnHeader); + + try { + Map jobj = request.send().getContentAsJSONObject(); + logger.info("Successful call"); + return jobj.get("access_token").toString(); + } catch (Exception e) { + throw new IOException(e.getMessage(), e); + } + + } + + private void setTimeouts(HTTPRequest request) { + request.setConnectTimeout(3500); + request.setReadTimeout(3500); + } + +} diff --git a/jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/extension/AdminMenu.java b/jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/extension/AdminMenu.java new file mode 100644 index 00000000000..5c0db84d743 --- /dev/null +++ b/jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/extension/AdminMenu.java @@ -0,0 +1,22 @@ +package io.jans.casa.plugins.acctlinking; + +import io.jans.casa.extension.navigation.MenuType; +import io.jans.casa.extension.navigation.NavigationMenu; +import org.pf4j.Extension; + +@Extension +public class AdminMenu implements NavigationMenu { + + public String getContentsUrl() { + return "admin/menu.zul"; + } + + public MenuType menuType() { + return MenuType.ADMIN_CONSOLE; + } + + public float getPriority() { + return 0.1f; + } + +} diff --git a/jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/extension/UserMenu.java b/jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/extension/UserMenu.java new file mode 100644 index 00000000000..d16c16a6dd7 --- /dev/null +++ b/jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/extension/UserMenu.java @@ -0,0 +1,23 @@ +package io.jans.casa.plugins.acctlinking; + +import io.jans.casa.extension.navigation.MenuType; +import io.jans.casa.extension.navigation.NavigationMenu; +import org.pf4j.Extension; + +@Extension +public class UserMenu implements NavigationMenu { + + public String getContentsUrl() { + return "user/menu.zul"; + } + + public MenuType menuType() { + return MenuType.USER; + } + + public float getPriority() { + return 0.1f; + } + +} + diff --git a/jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/vm/AccountsLinkingSettingsVM.java b/jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/vm/AccountsLinkingSettingsVM.java new file mode 100644 index 00000000000..eaddb34e869 --- /dev/null +++ b/jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/vm/AccountsLinkingSettingsVM.java @@ -0,0 +1,42 @@ +package io.jans.casa.plugins.acctlinking.vm; + +import io.jans.casa.plugins.acctlinking.AccountsLinkingService; +import io.jans.inbound.Provider; + +import java.util.*; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.zkoss.bind.annotation.Init; + +public class AccountsLinkingSettingsVM { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + private String error; + + private Map providers = Collections.emptyMap(); + + public Map getProviders() { + return providers; + } + + public String getError() { + return error; + } + + @Init + public void init() { + + try { + logger.info("Refreshing list of identity providers"); + providers = AccountsLinkingService.getInstance().getProviders(false); + } catch (Exception e) { + providers = null; + error = e.getMessage(); + logger.error(error, e); + } + + } + +} diff --git a/jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/vm/AccountsLinkingVM.java b/jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/vm/AccountsLinkingVM.java new file mode 100644 index 00000000000..c311d02f5b6 --- /dev/null +++ b/jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/vm/AccountsLinkingVM.java @@ -0,0 +1,143 @@ +package io.jans.casa.plugins.acctlinking.vm; + +import io.jans.inbound.Provider; +import io.jans.casa.plugins.acctlinking.AccountsLinkingService; +import io.jans.casa.service.ISessionContext; +import io.jans.casa.ui.UIUtils; + +import java.util.*; +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.zkoss.bind.BindUtils; +import org.zkoss.bind.annotation.*; +import org.zkoss.util.resource.Labels; +import org.zkoss.zk.ui.Component; +import org.zkoss.zk.ui.event.Event; +import org.zkoss.zk.ui.event.EventQueues; +import org.zkoss.zk.ui.select.annotation.WireVariable; +import org.zkoss.zul.Messagebox; + +public class AccountsLinkingVM { + + public static final String LINK_QUEUE = "social_queue"; + + public static final String EVENT_NAME = "linked"; + + public static final long ENROLL_TIME_MS = TimeUnit.MINUTES.toMillis(1); //1 min + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @WireVariable + private ISessionContext sessionContext; + + private AccountsLinkingService als; + private Map providers; + private Map accounts; + + private String userId; + private String pendingProvider; + private long pendingLinkingExpiresAt; + + public Map getProviders() { + return providers; + } + + public Map getAccounts() { + return accounts; + } + + public String getPendingProvider() { + return pendingProvider; + } + + public AccountsLinkingVM() { + als = AccountsLinkingService.getInstance(); + } + + @Init + public void init() { + + try { + logger.info("Refreshing list of identity providers"); + providers = als.getProviders(true); + logger.info("{} identity providers found", providers.size()); + + userId = sessionContext.getLoggedUser().getId(); + parseLinkedAccounts(); + + if (providers.size() > 0) { + + EventQueues.lookup(LINK_QUEUE, EventQueues.SESSION, true).subscribe(event -> { + if (event.getName().equals(EVENT_NAME)) { + + String data = Optional.ofNullable(event.getData()).map(Object::toString).orElse(null); + if (data != null) { + logger.info("Received link start event for {}", data); + pendingLinkingExpiresAt = System.currentTimeMillis() + ENROLL_TIME_MS; + pendingProvider = data; + } else { + logger.info("Received linked event"); + cancel(); + parseLinkedAccounts(); + } + BindUtils.postNotifyChange(AccountsLinkingVM.this, "accounts", "pendingProvider"); + } + }); + } + + } catch (Exception e) { + logger.error(e.getMessage()); + } + + } + + @NotifyChange("pendingProvider") + public void cancel() { + pendingProvider = null; + } + + @Command + public void poll() { + + if (pendingProvider != null && pendingLinkingExpiresAt < System.currentTimeMillis()) { + logger.info("Too much time elapsed for linking to finish"); + cancel(); + //I could have used @NotifyChange("pendingProvider") in this method but postnotify will give + //better performance here. UI refresh takes place only if this IF is reached + BindUtils.postNotifyChange(AccountsLinkingVM.this, "pendingProvider"); + } + + } + + public void remove(String providerId, String extUid) { + + if (accounts.size() > 1 || als.hasPassword(userId)) { + Provider p = providers.get(providerId); + + Messagebox.show(Labels.getLabel("al.remove_hint"), null, Messagebox.YES | Messagebox.NO, Messagebox.QUESTION, + event -> { + if (Messagebox.ON_YES.equals(event.getName())) { + + if (als.delink(userId, providerId, extUid)) { + parseLinkedAccounts(); + UIUtils.showMessageUI(true, Labels.getLabel("al.removed_link", new String[]{ p.getDisplayName() })); + BindUtils.postNotifyChange(AccountsLinkingVM.this, "accounts"); + } else { + UIUtils.showMessageUI(false); + } + } + }); + } else { + Messagebox.show(Labels.getLabel("al.linking_pass_needed"), null, Messagebox.OK, Messagebox.INFORMATION); + } + + } + + private void parseLinkedAccounts() { + logger.info("Parsing linked accounts for {}", userId); + accounts = als.getAccounts(userId, providers.keySet()); + } + +} diff --git a/jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/vm/SiteRedirectVM.java b/jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/vm/SiteRedirectVM.java new file mode 100644 index 00000000000..ecc82f4237f --- /dev/null +++ b/jans-casa/plugins/acct-linking/src/main/java/io/jans/casa/plugins/acctlinking/vm/SiteRedirectVM.java @@ -0,0 +1,179 @@ +package io.jans.casa.plugins.acctlinking.vm; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +import io.jans.casa.conf.OIDCClientSettings; +import io.jans.casa.misc.Utils; +import io.jans.casa.misc.WebUtils; +import io.jans.casa.service.IPersistenceService; +import io.jans.casa.service.ISessionContext; +import io.jans.casa.plugins.acctlinking.AccountsLinkingService; +import io.jans.inbound.oauth2.OAuthParams; +import io.jans.inbound.oauth2.CodeGrantUtil; +import io.jans.service.cache.*; +import io.jans.util.Pair; + +import java.util.*; +import java.util.stream.Collectors; +import java.net.*; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.zkoss.bind.annotation.Init; +import org.zkoss.bind.annotation.QueryParam; +import org.zkoss.util.resource.Labels; +import org.zkoss.zk.ui.Sessions; +import org.zkoss.zk.ui.event.Event; +import org.zkoss.zk.ui.event.EventQueues; +import org.zkoss.zk.ui.select.annotation.WireVariable; + +public class SiteRedirectVM { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + private static final String STATE_ATTR = "st"; + + @WireVariable + private ISessionContext sessionContext; + + private CacheInterface cache; + private AccountsLinkingService als; + private ObjectMapper mapper; + + private String serverUrl; + private String userName; + + private String text; + private String title; + + public String getText() { + return text; + } + + public String getTitle() { + return title; + } + + public SiteRedirectVM() { + als = AccountsLinkingService.getInstance(); + mapper = new ObjectMapper(); + serverUrl = Utils.managedBean(IPersistenceService.class).getIssuerUrl(); + cache = Utils.managedBean(CacheInterface.class); + } + + @Init + public void init(@QueryParam("provider") String provider) { + + try { + logger.debug("Initializing ViewModel"); + userName = sessionContext.getLoggedUser().getUserName(); + + title = Labels.getLabel("general.error.general"); + String currentUrl = WebUtils.getServletRequest().getRequestURL().toString(); + + CodeGrantUtil cgu = new CodeGrantUtil(makeOAuthParams(als.getCasaClient(), provider, currentUrl)); + + if (Utils.isNotEmpty(provider)) { + text = Labels.getLabel("al.link_redirect_failed", new String[]{ provider }); + String url = getAuthzRequestRedirectUrl(cgu); + + EventQueues.lookup(AccountsLinkingVM.LINK_QUEUE, EventQueues.SESSION, true) + .publish(new Event(AccountsLinkingVM.EVENT_NAME, null, provider)); + WebUtils.execRedirect(url, false); + + } else { + + //Agama authn flow finished + String state = Optional.ofNullable(Sessions.getCurrent().getAttribute(STATE_ATTR)) + .map(Object::toString).orElse(null); + + if (state == null) return; + + Map mama = WebUtils.getServletRequest().getParameterMap().entrySet().stream() + .map(entry -> { + String[] val = entry.getValue(); + List values = (val == null || val.length == 0) ? + Collections.emptyList() : Arrays.asList(val); + return new AbstractMap.SimpleEntry<>(entry.getKey(), values); + }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + + String code = cgu.parseCode(mama, state); + + logger.info("Got an authz code at callback URL"); + //If the token request succeeds, ie. does not throw, it means the code is not fake + cgu.getTokenResponse(code); + + logger.info("Notifying linking page..."); + EventQueues.lookup(AccountsLinkingVM.LINK_QUEUE, EventQueues.SESSION, true) + .publish(new Event(AccountsLinkingVM.EVENT_NAME, null, null)); + + title = Labels.getLabel("al.linking_result.success"); + text = Labels.getLabel("al.linking_result.success_close"); + } + + } catch (Exception e) { + text = e.getMessage(); + logger.error(text, e); + } + + } + + private String getAuthzRequestRedirectUrl(CodeGrantUtil cgu) throws URISyntaxException { + + logger.info("Building an agama authentication request"); + Pair pair = cgu.makeAuthzRequest(); + + Sessions.getCurrent().setAttribute(STATE_ATTR, pair.getSecond()); + return pair.getFirst(); + + } + + private OAuthParams makeOAuthParams(OIDCClientSettings cl, String provider, String redirectUri) { + + OAuthParams p = new OAuthParams(); + p.setAuthzEndpoint(serverUrl + "/jans-auth/restv1/authorize"); + p.setTokenEndpoint(serverUrl + "/jans-auth/restv1/token"); + p.setClientId(cl.getClientId()); + p.setClientSecret(cl.getClientSecret()); + p.setScopes(Collections.singletonList("openid")); + p.setRedirectUri(redirectUri); + + Map custMap = new HashMap<>(); + + if (provider != null) { + custMap.put("acr_values", "agama"); + custMap.put("agama_flow", makeAgamaFlowParam(provider)); + } + + //prompt is needed because the user could have previously linked an account and in a new + //attempt to link at a different provider, launching an authn request will not trigger the + //agama flow because there is "existing" session in the AS + custMap.put("prompt", "login"); + p.setCustParamsAuthReq(custMap); + return p; + + } + + private String makeAgamaFlowParam(String provider) { + + String key = "" + Math.random(); + int sec = Long.valueOf(AccountsLinkingVM.ENROLL_TIME_MS).intValue() / 1000; + + logger.debug("Writing uid ref to cache"); + //What is stored here will be later retrieved by the agama flow. Twice the casa enrollment time + //given. This is to avoid the not very user-friendly error "uid reference passed not found in Cache!" + cache.put(2 * sec, key, userName); + + String s = null; + try { + s = mapper.writeValueAsString(Map.of("providerId", provider, "uidRef", key)); + } catch (JsonProcessingException e) { + //this will never happen + logger.error(e.getMessage()); + } + return als.CASA_AGAMA_FLOW + "-" + s; + + } + +} diff --git a/jans-casa/plugins/acct-linking/src/main/resources/assets/admin/al-settings.zul b/jans-casa/plugins/acct-linking/src/main/resources/assets/admin/al-settings.zul new file mode 100644 index 00000000000..622b37edfc3 --- /dev/null +++ b/jans-casa/plugins/acct-linking/src/main/resources/assets/admin/al-settings.zul @@ -0,0 +1,59 @@ + + + + + + ${zkService.appName} - ${labels.al.title} + + + + + +
+
+ +
+

${labels.al.title}

+
+
+

${labels.al.adm.intro_text}

+ +

${labels.al.adm.no_providers}

+ +

${labels.al.adm.error_retrieve}

+ + + + + + + + + ${labels.al.adm.name} + ${labels.al.adm.flow} + ${labels.al.adm.mapping} + ${labels.al.adm.status} + + + + + + ${each.value.displayName} + ${each.value.flowQname} + ${each.value.mappingClassField} + + + + + +
+
+
+
+ +
diff --git a/jans-casa/plugins/acct-linking/src/main/resources/assets/admin/menu.zul b/jans-casa/plugins/acct-linking/src/main/resources/assets/admin/menu.zul new file mode 100644 index 00000000000..85511e0027a --- /dev/null +++ b/jans-casa/plugins/acct-linking/src/main/resources/assets/admin/menu.zul @@ -0,0 +1,10 @@ + + +
  • + + ${labels.al.title} + +
  • + + diff --git a/jans-casa/plugins/acct-linking/src/main/resources/assets/user/index.zul b/jans-casa/plugins/acct-linking/src/main/resources/assets/user/index.zul new file mode 100644 index 00000000000..6326a7f3210 --- /dev/null +++ b/jans-casa/plugins/acct-linking/src/main/resources/assets/user/index.zul @@ -0,0 +1,79 @@ + + + + + ${zkService.appName} - ${labels.al.title} + + + + + + + +
    +
    +
    +

    ${labels.al.title}

    +

    + +

    + + +
    +
    + + + +
    + +
    diff --git a/jans-casa/plugins/acct-linking/src/main/resources/assets/user/interlude.zul b/jans-casa/plugins/acct-linking/src/main/resources/assets/user/interlude.zul new file mode 100644 index 00000000000..97c57ea4906 --- /dev/null +++ b/jans-casa/plugins/acct-linking/src/main/resources/assets/user/interlude.zul @@ -0,0 +1,17 @@ + + + + +
    +
    +
    +

    ${vm.title}

    +
    +
    +

    ${vm.text}

    +
    +
    +
    + +
    diff --git a/jans-casa/plugins/acct-linking/src/main/resources/assets/user/menu.zul b/jans-casa/plugins/acct-linking/src/main/resources/assets/user/menu.zul new file mode 100644 index 00000000000..450d6cc0971 --- /dev/null +++ b/jans-casa/plugins/acct-linking/src/main/resources/assets/user/menu.zul @@ -0,0 +1,10 @@ + + +
  • + + + ${labels.al.title} + +
  • + +
    diff --git a/jans-casa/plugins/acct-linking/src/main/resources/labels/zk-label.properties b/jans-casa/plugins/acct-linking/src/main/resources/labels/zk-label.properties new file mode 100644 index 00000000000..d59d7b660ff --- /dev/null +++ b/jans-casa/plugins/acct-linking/src/main/resources/labels/zk-label.properties @@ -0,0 +1,56 @@ +# Admin section + +al.title=Accounts Linking + +al.nothing_yet=Nothing to show here yet. Contact your administrator. + +al.intro_text=Link accounts you own at external sites, for instance social networks. + +al.link_unavailable=Not linked + +al.link_status=Linked to user + +al.buttons.link=Link +al.buttons.linking=Linking ... + +al.buttons.remove=Remove + +al.buttons.cancel=Cancel + +al.remove_hint=Are you sure you want to remove this linked account? + +al.removed_link=The association with your account at {0} was removed. + +# usr.password_set.title is defined in core casa project (user.properties) +al.linking_pass_needed={ +To remove your only linked account, you have to set a password first. This will allow you to still have means +to access this application in the future. + +Click on "${usr.password_set.title}" to do so. +} + +al.link_redirect_failed=Redirecting to site "{0}" was not possible + +al.linking_result.success=Your account has been linked successfully + +al.linking_result.success_close=You can close this window now. + +## Admin labels + +al.adm.learn_config=Check the plugin docs to learn how to manage external identity providers. + +al.adm.intro_text=This is the list of external identity providers configured so far. ${al.adm.learn_config} + +al.adm.no_providers=There are no providers defined yet. ${al.adm.learn_config} + +al.adm.error_retrieve=Unable to retrieve the list of external identity providers. ${al.adm.learn_config} + +al.adm.name=Name + +al.adm.status=Enabled + +al.adm.flow=Agama flow + +al.adm.mapping=Profile attribute mapping + + diff --git a/jans-casa/pom.xml b/jans-casa/pom.xml index 70b1a361b74..0a7572b91ab 100644 --- a/jans-casa/pom.xml +++ b/jans-casa/pom.xml @@ -61,6 +61,7 @@ shared app app-fips + plugins/acct-linking plugins/client-authorizations plugins/custom-branding plugins/strong-authn-settings From 46be9539572ad948ded1c3fba23378d630b40e01 Mon Sep 17 00:00:00 2001 From: jgomer2001 Date: Mon, 18 Mar 2024 11:47:38 -0500 Subject: [PATCH 3/4] docs: update docs #7556 Signed-off-by: jgomer2001 --- docs/casa/index.md | 1 + .../accts-linking/accts-linking-agama.md | 87 ++++++++++++++++ docs/casa/plugins/accts-linking/index.md | 99 +++++++++++++++++++ mkdocs.yml | 1 + 4 files changed, 188 insertions(+) create mode 100644 docs/casa/plugins/accts-linking/accts-linking-agama.md create mode 100644 docs/casa/plugins/accts-linking/index.md diff --git a/docs/casa/index.md b/docs/casa/index.md index 6b081e52a1d..6cf4b57fc40 100644 --- a/docs/casa/index.md +++ b/docs/casa/index.md @@ -50,6 +50,7 @@ Besides a comprehensive graphical [admin console](./administration/admin-console Casa is a plugin-oriented, Java web application. Existing functionality can be extended and new functionality and APIs can be introduced through plugins. Currently, there are plugins available for the following: +- [Accounts linking](./plugins/accts-linking/index.md) - [Consent management](./plugins/consent-management.md) - [Custom branding](./plugins/custom-branding.md) - [2FA settings](./plugins/2fa-settings.md) diff --git a/docs/casa/plugins/accts-linking/accts-linking-agama.md b/docs/casa/plugins/accts-linking/accts-linking-agama.md new file mode 100644 index 00000000000..5fb93d8b343 --- /dev/null +++ b/docs/casa/plugins/accts-linking/accts-linking-agama.md @@ -0,0 +1,87 @@ +# Accounts linking project configuration + +## Overview + +The accounts linking Agama project must be configured in order to integrate third-party identity providers. The configuration of this project is supplied in a JSON file whose structure is like: + +``` +{ +"io.jans.casa.acctlinking.Launcher": { + + "providerID_1": { ... }, + "providerID_2": { ... }, + ... +} +} +``` + +Each property part of the JSON object `io.jans.casa.acctlinking.Launcher` holds the configuration of a different identity provider. Here's a how a typical configuration of a provider looks like: + +``` +{ + "displayName": "Goooogle", + "flowQname": "io.jans.inbound.GenericProvider", + "mappingClassField": "io.jans.casa.acctlinking.Mappings.GOOGLE", + "oauthParams": { + "authzEndpoint": "https://accounts.google.com/o/oauth2/v2/auth", + "tokenEndpoint": "https://oauth2.googleapis.com/token", + "userInfoEndpoint": "https://www.googleapis.com/oauth2/v3/userinfo", + "clientId": "202403151302", + "clientSecret": "m|a1l2d3i4t5a6S7h8a9k0i'r¿a", + "scopes": ["email", "profile"] + } +} + +``` + +In this case, we are populating the configuration of an OAuth-based provider called "Goooogle". + +The tables shown in [this](https://github.com/JanssenProject/jans/blob/main/docs/agama-catalog/jans/inboundID/README.md#supply-configurations) page list all possible properties to configure a provider. Particularly, two properties deserve the most detail: + +1. `flowQname`. Agama projects are made up of flows - think of small "web journeys". This property must contain the name of an existing flow capable of interfacing with the identity provider of interest. Often, there is no need to write such "interfacing" flow. The below are ready-to-use and cover most of real-world cases, specifically OpenId/OAuth providers that support the **authorization code grant** (see section 1.3 of [rfc6749](https://www.ietf.org/rfc/rfc6749)): + + - `io.jans.inbound.GenericProvider`. It implements the authorization code flow where the user's browser is taken to the external site. When authentication completes, a `code` is received at a designated redirect (callback) URL. With such `code` an access token is obtained as well as user's profile data. This flow supports _dynamic client registration_ + + - `io.jans.inbound.Apple`. It implements the authorization code flow with some nuances required in order to integrate "Apple Sign In" + + +2. `mappingClassField`. This is key for performing the attribute mapping process and the user provisioning. The remainder of this document is dedicated to these two aspects + +!!! Note + Recall `enabled` is a handy property that can be used to temporarily "deactive" a given identity provider. + +## Configuring attribute mappings + +An introduction to attribute mapping can be found [here](https://github.com/JanssenProject/jans/blob/main/docs/agama-catalog/jans/inboundID/README.md#attribute-mappings). Unless an elaborated processing of attributes is required, a basic knowledge of Java language suffices to write a useful mapping. + +To write a mapping, you can use the samples provided as a guideline (see folder `lib/io/jans/casa/acctlinking` in the Agama accounts linking project). You can add your mapping in the same file or create a new Java class for this purpose. Then save your changes, re-package (zip) the project, re-deploy, and update (re-import) the configuration if necessary. + +Specifically, for Casa accounts linking, the mapping **must** include an attribute named `ID`. While `ID` is not part of the Jans database, here it is used to supply what could be understood as the _identifier_ of the user at the external site. For instance, in a social site this may be the username or email. The example below shows how to set `ID` assuming the username was returned by the external site in an attribute named `userId`: + +``` +profile -> { + Map map = new HashMap<>(); + + map.put("ID", profile.get("userId")); + ... + return map; +} +``` + +In the above example, `profile` is a `Map` that holds the attribute-value pairs the third-party identity provider released for this user. For the interested, `profile` contents are dumped to the server logs (check `jans-auth_script.log`) so it is easy to peak into the values. Check for a message in `debug` level starting with "Profile data". + +Both the ID of identity provider and the ID of the user will end up stored in an auxiliary database attribute. This helps to identify if the incoming user is already known (has been onboarded previously). + +When the attribute mapping is applied, the `uid` attribute is set as well. This is the username the incoming user will be assigned in the local Jans database. The `uid` is automatically generated based on `ID` unless the mapping already populates the `uid` directly. + +The return value of the mapping is a `Map`. This caters for cases where resulting attributes hold booleans, dates, numbers, strings, etc. When the attribute has to hold multiple values, you can use an array or a Java `Collection` object, like a `List`. + +## User provisioning + +After attribute mapping occurs, the local database is checked to determine if the incoming user is known (based on the `ID` in the mapping and the ID of the provider in question). If no match is found, the user is onboarded: a new entry is created in the database using the information found in the resulting mapping. Otherwise, the exact behavior varies depending on the provider configuration as follows: + +- If `skipProfileUpdate` is set to `false`, the existing database entry is left untouched, otherwise +- If `cumulativeUpdate` is set to `false`, the existing attributes in the entry which are part of the mapping are overwritten +- If `cumulativeUpdate` is set to `true`, the existing attribute values in the entry are preserved and new values are added if present in the mapping + +The updates just referenced apply to the matching entry based on mapping and provider ID, however, when `emailLinkingSafe` is set to `true` and the mapping comes with a `mail` value equal to an existing e-mail in the database, the update is carried over the e-mail matching entry. diff --git a/docs/casa/plugins/accts-linking/index.md b/docs/casa/plugins/accts-linking/index.md new file mode 100644 index 00000000000..5225ab4afef --- /dev/null +++ b/docs/casa/plugins/accts-linking/index.md @@ -0,0 +1,99 @@ +# Accounts Linking Plugin + +## Overview + +This plugin allows users to "link" their local Jans account with existing accounts at third-party identity providers like OIDC OPs and social sites, e.g. Apple, Facebook, Google, etc. + +Besides the usual onboarding of a plugin jar file in Casa, administrators must deploy a number of additional components. This will be regarded later. By now let's summary key points of the accounts linking experience: + +- When a user tries to login to Casa, the usual username/password form is presented but also a list of links that can take him to external sites (third-party identity providers) where authentication takes place +- Once authenticated, user profile data is grabbed from the external site - this is all backchannel +- A process called _attribute mapping_ is performed on profile data. This is a transformation process that turns incoming profile data into a shape compatible with a regular Jans database user entry +- If the mapped profile data matches an existing user in the Jans database, the existing entry is updated with the incoming data, otherwise, a new entry is inserted - this is called _user provisioning_. When provisioning occurs, the account has no password associated +- Finally the user is given access to Casa + +From the perspective of a user already logged into Casa, the experience is as follows: + +- In casa, a menu item is provided which takes the user to a (Casa) page that shows a list of third-party identity providers. For every provider there are options to trigger linking in case there is no account linked yet (external site authentication is launched), or to remove the linked account from the user profile +- If an account has no password assigned, removal of linked accounts is not allowed. However, a functionality for the user to assign himself a password is provided + +## Components deployment + +The pieces that allow materialization of the experience summarized above are the following: + +a) The Casa plugin jar file + +b) A custom XHTML page and jython script + +c) The Agama inbound identity project + +d) The Casa accounts linking Agama project + +Most of work is demanded on setting up project _d_, where configuration of identity providers and attribute mapping tuning takes place. + +In the following, it is assumed you have a VM-based installation of Jans Server (or Gluu Flex) available with Casa installed. In a separate machine, ensure you have SSH/SCP/SFTP access to such server and `git` installed. + +!!! Note + For the below instructions ensure to replace `` with the version of your Jans Server + +1. Download the plugin jar file `https://maven.jans.io/maven/io/jans/casa/plugins/acct-linking//acct-linking--jar-with-dependencies.jar` and copy to your server's `/opt/jans/jetty/jans-casa/plugins` + +1. Download the utility jar file `https://maven.jans.io/maven/io/jans/agama-inbound//agama-inbound-.jar` and copy to your server's `/opt/jans/jetty/jans-auth/custom/libs` + +1. In the server, create a `casa` directory inside `/opt/jans/jetty/jans-auth/custom/pages` + +1. Download the file `https://github.com/JanssenProject/jans/raw/main/jans-casa/plugins/acct-linking/extras/login.xhtml` and copy it to the previously created folder + +1. Download the file `https://github.com/JanssenProject/jans/raw/main/jans-casa/plugins/acct-linking/extras/Casa.py`. Open TUI or the admin UI (for Flex), and locate the custom script whose name is `casa`. Update the contents of the script with the contents of the file + +1. In TUI, ensure the custom script named `agama` is enabled + +1. Still in TUI, visit the Clients screen, locate the client labeled "Client for Casa". Add the following redirect URI to the list: `https:///jans-casa/pl/acct-linking/user/interlude.zul`. Replace the name of your Jans server accordingly + +1. Run the following commands to generate the archives of the Agama projects + + ``` + git clone --depth 1 --branch main --no-checkout https://github.com/JanssenProject/jans.git + cd jans + git sparse-checkout init --cone + git sparse-checkout set docs/agama-catalog/jans/inboundID/project + git sparse-checkout set jans-casa/plugins/acct-linking/extras/agama + git checkout main + cd docs/agama-catalog/jans/inboundID/project + zip -r inbound.zip * + cd jans-casa/plugins/acct-linking/extras/agama + zip -r acctlinking.zip * + ``` + +1. Transfer the zip files to a location in the server, deploy both archives using TUI (Agama menu) + +1. Finally restart the authentication server + +## Configuration + +So far all components required for the Casa inbound identity solution are loaded in the server. When logging to casa, the form presented looks like usual, and once in, the "Accounts linking" menu takes to a page which hints about missing configuration. + +The first step is figuring out the external sites to support. Keep in mind only OpenID or OAuth 2.0 based providers can be onboarded. There is not support for SAML IDPs. + +The procedures for getting configuration settings in order to integrate third party providers vary widely. Here, only basic guidelines are given: + +- If the provider is OpenId-compliant and supports dynamic client registration, obtain the OP URL and the scopes list to use when requesting user profile information. Most of times the scopes `openid`, `profile` and `email` will fit the bill + +- If the provider is OpenId-compliant and does not support dynamic client registration, obtain the OP URL and scopes as in the previous case, and also a client ID and secret + +- If the provider does not support OpenId. Obtain the following: + + - The authorization endpoint URL + - The token endpoint URL + - The endpoint URL where profile data can be retrieved + - Client credentials (ID and secret) + - Scopes to use when requesting user profile information + +The steps required to grab the above data vary among providers. Normally this is obtained through a sort of administrative developer GUI tool. If you are prompted for a "redirect URI" in such tool, provide `https:///jans-auth/fl/callback`. + +Now it's time to supply the settings grabbed. The component these configurations are injected to is the Casa accounts linking Agama project. To make the effort easier, this project is bundled with some dummy configuration properties you can use as a template. Proceed as follows: + +1. In TUI, open the Agama tab and scroll through the list of projects until the `casa-account-linking` is highlighted +1. Open the configuration management dialog (press `c`) and choose to export the sample configuration to a file on disk +1. Apply changes as needed - this is covered in a separate doc page [here](./accts-linking-agama.md). Note you can add or remove sections in the file at will, and that providers can also be disabled so they are not listed in the login page or in Casa app +1. Still in TUI, choose to import the file you have edited. Then conduct your testing diff --git a/mkdocs.yml b/mkdocs.yml index 7ec5213ee9a..fd201f38f61 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -448,6 +448,7 @@ nav: - 'Localization': 'casa/administration/localization.md' - 'Plugins': - '2FA Settings': 'casa/plugins/2fa-settings.md' + - 'Accounts Linking': 'casa/plugins/accts-linking/index.md' - 'Consent Management': 'casa/plugins/consent-management.md' - 'Custom Branding': 'casa/plugins/custom-branding.md' - 'FAQ': 'casa/administration/faq.md' From 6281f1e5df5f49001e672695f4ec9bcac6207187 Mon Sep 17 00:00:00 2001 From: jgomer2001 Date: Tue, 19 Mar 2024 09:16:21 -0500 Subject: [PATCH 4/4] docs: minor rephrasing #7556 Signed-off-by: jgomer2001 --- docs/casa/plugins/accts-linking/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/casa/plugins/accts-linking/index.md b/docs/casa/plugins/accts-linking/index.md index 5225ab4afef..2b38548cf80 100644 --- a/docs/casa/plugins/accts-linking/index.md +++ b/docs/casa/plugins/accts-linking/index.md @@ -4,7 +4,7 @@ This plugin allows users to "link" their local Jans account with existing accounts at third-party identity providers like OIDC OPs and social sites, e.g. Apple, Facebook, Google, etc. -Besides the usual onboarding of a plugin jar file in Casa, administrators must deploy a number of additional components. This will be regarded later. By now let's summary key points of the accounts linking experience: +Besides the usual onboarding of a plugin jar file in Casa, administrators must deploy a number of additional components. This will be regarded later. However let's summary the key points of the accounts linking experience: - When a user tries to login to Casa, the usual username/password form is presented but also a list of links that can take him to external sites (third-party identity providers) where authentication takes place - Once authenticated, user profile data is grabbed from the external site - this is all backchannel