def sendDevicePushNotification(self, user, app_id, u2f_device, super_gluu_request): device_data = u2f_device.getDeviceData() if device_data == None: return {"send_android":0,"send_ios":0} platform = device_data.getPlatform() push_token = device_data.getPushToken() pushNotificationContext = PushNotificationContext(app_id,super_gluu_request) pushNotificationContext.debugEnabled = self.debugEnabled pushNotificationContext.user = user pushNotificationContext.u2fDevice = u2f_device pushNotificationContext.devicePlatform = platform pushNotificationContext.pushToken = push_token send_ios = 0 send_android = 0 if StringHelper.equalsIgnoreCase(platform,"ios") and StringHelper.isNotEmpty(push_token): # Sending notification to iOS user's device if self.pushAppleService == None: print "Super-Gluu-Push. Apple push notification service disabled" else: self.sendApplePushNotification(pushNotificationContext) send_ios = 1 if StringHelper.equalsIgnoreCase(platform,"android") and StringHelper.isNotEmpty(push_token): # Sending notification to android user's device if self.pushAndroidService == None: print "Super-Gluu-Push. Android push notification service disabled" else: self.sendAndroidPushNotification(pushNotificationContext) send_android = 1 return {"send_android":send_android,"send_ios":send_ios}
def lockUser(self, user_name): if StringHelper.isEmpty(user_name): return None userService = CdiUtil.bean(UserService) cacheService= CdiUtil.bean(CacheService) facesMessages = CdiUtil.bean(FacesMessages) facesMessages.setKeepMessages() find_user_by_uid = userService.getUser(user_name) if (find_user_by_uid == None): return None status_attribute_value = userService.getCustomAttribute(find_user_by_uid, "gluuStatus") if status_attribute_value != None: user_status = status_attribute_value.getValue() if StringHelper.equals(user_status, "inactive"): print "Basic (lock account). Lock user. User '%s' locked already" % user_name return userService.setCustomAttribute(find_user_by_uid, "gluuStatus", "inactive") updated_user = userService.updateUser(find_user_by_uid) object_to_store = json.dumps({'locked': True, 'created': LocalDateTime.now().toString()}, separators=(',',':')) cacheService.put(StringHelper.toString(self.lockExpirationTime), "lock_user_"+user_name, object_to_store); facesMessages.add(FacesMessage.SEVERITY_ERROR, "Your account is locked. Please try again after " + StringHelper.toString(self.lockExpirationTime) + " secs") print "Basic (lock account). Lock user. User '%s' locked" % user_name
def is_session_authenticated(self, sessionId): if sessionId == None: return False state = sessionId.getState() custom_state = sessionId.getSessionAttributes().get(SessionIdService.SESSION_CUSTOM_STATE) if state == None: print "Super-Gluu-RO. Session {%s} has no state variable set" % sessionId.getId() return False state_unauthenticated = SessionIdState.UNAUTHENTICATED == state state_authenticated = SessionIdState.AUTHENTICATED == state custom_state_declined = StringHelper.equalsIgnoreCase("declined",custom_state) custom_state_expired = StringHelper.equalsIgnoreCase("expired",custom_state) custom_stated_approved = StringHelper.equalsIgnoreCase("approved",custom_state) if state_unauthenticated and (custom_state_declined or custom_state_expired): print "Super-Gluu-RO. Session {%s} isn't authenticated" % sessionId.getId() return False if state_authenticated or (state_unauthenticated and custom_stated_approved): print "Super-Gluu-RO. Session {%s} is authenticated" % sessionId.getId() return True return False
def init(self, configurationAttributes): print "Basic (lock account). Initialization" self.invalidLoginCountAttribute = "oxCountInvalidLogin" if configurationAttributes.containsKey("invalid_login_count_attribute"): self.invalidLoginCountAttribute = configurationAttributes.get("invalid_login_count_attribute").getValue2() else: print "Basic (lock account). Initialization. Using default attribute" self.maximumInvalidLoginAttemps = 3 if configurationAttributes.containsKey("maximum_invalid_login_attemps"): self.maximumInvalidLoginAttemps = StringHelper.toInteger(configurationAttributes.get("maximum_invalid_login_attemps").getValue2()) else: print "Basic (lock account). Initialization. Using default number attempts" self.lockExpirationTime = 180 if configurationAttributes.containsKey("lock_expiration_time"): self.lockExpirationTime = StringHelper.toInteger(configurationAttributes.get("lock_expiration_time").getValue2()) else: print "Basic (lock account). Initialization. Using default lock expiration time" print "Basic (lock account). Initialized successfully. invalid_login_count_attribute: '%s', maximum_invalid_login_attemps: '%s', lock_expiration_time: '%s'" % (self.invalidLoginCountAttribute, self.maximumInvalidLoginAttemps, self.lockExpirationTime) return True
def authenticate_user_credentials(self, identity, authentication_service): credentials = identity.getCredentials() user_name = credentials.getUsername() user_password = credentials.getPassword() print "ThumbSignIn. user_name: " + user_name logged_in = False if StringHelper.isNotEmptyString(user_name) and StringHelper.isNotEmptyString(user_password): logged_in = self.authenticate_user_in_gluu_ldap(authentication_service, user_name, user_password) return logged_in
def verify_session_ownership(self, sessionId, user, client): session_attributes = sessionId.getSessionAttributes() client_id = session_attributes.get(self.clientIdSessionParamName) if not StringHelper.equalsIgnoreCase(client.getClientId(),client_id): print "Super-Gluu-RO. Session {%s} client_id mismatch" % sessionId.getId() return False user_id = session_attributes.get(Constants.AUTHENTICATED_USER) if not StringHelper.equalsIgnoreCase(user_id,user.getUserId()): print "Super-Gluu-RO. Session {%s} user_id mismatch" % sessionId.getId() return False return True
def init(self, configurationAttributes): print "Cert. Initialization" if not (configurationAttributes.containsKey("chain_cert_file_path")): print "Cert. Initialization. Property chain_cert_file_path is mandatory" return False if not (configurationAttributes.containsKey("map_user_cert")): print "Cert. Initialization. Property map_user_cert is mandatory" return False chain_cert_file_path = configurationAttributes.get("chain_cert_file_path").getValue2() self.chain_certs = CertUtil.loadX509CertificateFromFile(chain_cert_file_path) if self.chain_certs == None: print "Cert. Initialization. Failed to load chain certificates from '%s'" % chain_cert_file_path return False print "Cert. Initialization. Loaded '%d' chain certificates" % self.chain_certs.size() crl_max_response_size = 5 * 1024 * 1024 # 10Mb if configurationAttributes.containsKey("crl_max_response_size"): crl_max_response_size = StringHelper.toInteger(configurationAttributes.get("crl_max_response_size").getValue2(), crl_max_response_size) print "Cert. Initialization. CRL max response size is '%d'" % crl_max_response_size # Define array to order methods correctly self.validator_types = [ 'generic', 'path', 'ocsp', 'crl'] self.validators = { 'generic' : [GenericCertificateVerifier(), False], 'path' : [PathCertificateVerifier(False), False], 'ocsp' : [OCSPCertificateVerifier(), False], 'crl' : [CRLCertificateVerifier(crl_max_response_size), False] } for type in self.validator_types: validator_param_name = "use_%s_validator" % type if configurationAttributes.containsKey(validator_param_name): validator_status = StringHelper.toBoolean(configurationAttributes.get(validator_param_name).getValue2(), False) self.validators[type][1] = validator_status print "Cert. Initialization. Validation method '%s' status: '%s'" % (type, self.validators[type][1]) self.map_user_cert = StringHelper.toBoolean(configurationAttributes.get("map_user_cert").getValue2(), False) print "Cert. Initialization. map_user_cert: '%s'" % self.map_user_cert self.enabled_recaptcha = self.initRecaptcha(configurationAttributes) print "Cert. Initialization. enabled_recaptcha: '%s'" % self.enabled_recaptcha print "Cert. Initialized successfully" return True
def processKeyStoreProperties(self, attrs): file = attrs.get("key_store_file") password = attrs.get("key_store_password") if file != None and password != None: file = file.getValue2() password = password.getValue2() if StringHelper.isNotEmpty(file) and StringHelper.isNotEmpty(password): self.keyStoreFile = file self.keyStorePassword = password return True print "Passport. readKeyStoreProperties. Properties key_store_file or key_store_password not found or empty" return False
def getGeolocation(self, identity): session_attributes = identity.getSessionId().getSessionAttributes() if session_attributes.containsKey("remote_ip"): remote_ip = session_attributes.get("remote_ip") 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 authenticate(self, context): if self.perform_preliminary_user_authentication(context) == False: print "Super-Gluu-Radius. User authentication state not validated" return False step = context.getHttpRequest().getParameter(self.stepParamName) if StringHelper.equalsIgnoreCase(step,self.initiateAuthStepName): return self.initiate_authentication(context) elif StringHelper.equalsIgnoreCase(step,self.resendNotificationStepName): return self.resend_push_notification(context) elif StringHelper.equalsIgnoreCase(step,self.verifyAuthStepName): return self.verify_authentication(context) else: context.setUser(None) print "Super-Gluu-RO. Unknown authentication step '%s'" % step return False
def init(self, configurationAttributes): print "UAF. Initialization" if not configurationAttributes.containsKey("uaf_server_uri"): print "UAF. Initialization. Property uaf_server_uri is mandatory" return False self.uaf_server_uri = configurationAttributes.get("uaf_server_uri").getValue2() self.uaf_policy_name = "default" if configurationAttributes.containsKey("uaf_policy_name"): self.uaf_policy_name = configurationAttributes.get("uaf_policy_name").getValue2() self.send_push_notifaction = False if configurationAttributes.containsKey("send_push_notifaction"): self.send_push_notifaction = StringHelper.toBoolean(configurationAttributes.get("send_push_notifaction").getValue2(), False) self.registration_uri = None if configurationAttributes.containsKey("registration_uri"): self.registration_uri = configurationAttributes.get("registration_uri").getValue2() self.customQrOptions = {} if configurationAttributes.containsKey("qr_options"): self.customQrOptions = configurationAttributes.get("qr_options").getValue2() print "UAF. Initializing HTTP client" httpService = CdiUtil.bean(HttpService) self.http_client = httpService.getHttpsClient() http_client_params = self.http_client.getParams() http_client_params.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 15 * 1000) print "UAF. Initialized successfully. uaf_server_uri: '%s', uaf_policy_name: '%s', send_push_notifaction: '%s', registration_uri: '%s', qr_options: '%s'" % (self.uaf_server_uri, self.uaf_policy_name, self.send_push_notifaction, self.registration_uri, self.customQrOptions) print "UAF. Initialized successfully" return True
def getCountAuthenticationSteps(self, configurationAttributes): identity = CdiUtil.bean(Identity) if identity.isSetWorkingParameter("otp_count_login_steps"): return StringHelper.toInteger("%s" % identity.getWorkingParameter("otp_count_login_steps")) else: return 2
def init(self, configurationAttributes): print "User registration. Initialization" self.enable_user = StringHelper.toBoolean(configurationAttributes.get("enable_user").getValue2(), False) print "User registration. Initialized successfully" return True
def updateUser(self, user, configurationAttributes): attributes = user.getCustomAttributes() # Add new attribute preferredLanguage attrPrefferedLanguage = GluuCustomAttribute("preferredLanguage", "en-us") attributes.add(attrPrefferedLanguage) # Add new attribute userPassword attrUserPassword = GluuCustomAttribute("userPassword", "test") attributes.add(attrUserPassword) # Update givenName attribute for attribute in attributes: attrName = attribute.getName() if (("givenname" == StringHelper.toLowerCase(attrName)) and StringHelper.isNotEmpty(attribute.getValue())): attribute.setValue(StringHelper.removeMultipleSpaces(attribute.getValue()) + " (updated)") return True
def __init__(self, serviceMode, credentialsFile): self.pushSnsMode = False self.pushGluuMode = False self.pushNotificationsEnabled = False self.titleTemplate = "Super-Gluu" self.messageTemplate = "Super-Gluu login request to %s" self.debugEnabled = True self.httpConnTimeout = 15 * 1000 # in milliseconds creds = self.loadCredentials(credentialsFile) if creds == None: return None if StringHelper.equalsIgnoreCase(serviceMode,"sns"): self.initSnsPushNotifications(creds) elif StringHelper.equalsIgnoreCase(serviceMode,"gluu"): self.initGluuPushNotifications(creds) else: self.initNativePushNotifications(creds)
def isUserMemberOfGroup(self, user, attribute, group): is_member = False member_of_list = user.getAttributeValues(attribute) if (member_of_list != None): for member_of in member_of_list: if StringHelper.equalsIgnoreCase(group, member_of) or member_of.endswith(group): is_member = True break return is_member
def preRegistration(self, user, requestParameters, configurationAttributes): print "User registration. Pre method" userStatus = GluuStatus.INACTIVE # Disable/Enable registered user user.setStatus(userStatus) self.guid = StringHelper.getRandomString(16) user.setGuid(self.guid) return True
def unLockUser(self, user_name): if StringHelper.isEmpty(user_name): return None userService = CdiUtil.bean(UserService) cacheService= CdiUtil.bean(CacheService) find_user_by_uid = userService.getUser(user_name) if (find_user_by_uid == None): return None object_to_store = json.dumps({'locked': False, 'created': LocalDateTime.now().toString()}, separators=(',',':')) cacheService.put(StringHelper.toString(self.lockExpirationTime), "lock_user_"+user_name, object_to_store); userService.setCustomAttribute(find_user_by_uid, "gluuStatus", "active") userService.setCustomAttribute(find_user_by_uid, self.invalidLoginCountAttribute, None) updated_user = userService.updateUser(find_user_by_uid) print "Basic (lock account). Lock user. User '%s' unlocked" % user_name
def get_remote_ip_from_request(self, servletRequest): try: remote_ip = servletRequest.getHeader("X-FORWARDED-FOR") if StringHelper.isEmpty(remote_ip): remote_ip = servletRequest.getRemoteAddr() return remote_ip except: print "NetApi. Could not determine remote location: ", sys.exc_info()[1] return None
def processBasicAuthentication(self, credentials): userService = CdiUtil.bean(UserService) authenticationService = CdiUtil.bean(AuthenticationService) user_name = credentials.getUsername() user_password = credentials.getPassword() logged_in = False if StringHelper.isNotEmptyString(user_name) and StringHelper.isNotEmptyString(user_password): logged_in = authenticationService.authenticate(user_name, user_password) if not logged_in: return None find_user_by_uid = authenticationService.getAuthenticatedUser() if find_user_by_uid == None: print "UAF. Process basic authentication. Failed to find user '%s'" % user_name return None return find_user_by_uid
def getUserProfile(self, jwt): # Check if there is user profile jwt_claims = jwt.getClaims() user_profile_json = jwt_claims.getClaimAsString("data") if StringHelper.isEmpty(user_profile_json): print "Passport. getUserProfile. User profile missing in JWT token" user_profile = None else: user_profile = self.getProfileFromJson(user_profile_json) return (user_profile, user_profile_json)
def loadOtpConfiguration(self, configurationAttributes): print "OTP. Load OTP configuration" if not configurationAttributes.containsKey("otp_conf_file"): return False otp_conf_file = configurationAttributes.get("otp_conf_file").getValue2() # Load configuration from file f = open(otp_conf_file, 'r') try: otpConfiguration = json.loads(f.read()) except: print "OTP. Load OTP configuration. Failed to load configuration from file:", otp_conf_file return False finally: f.close() # Check configuration file settings try: self.hotpConfiguration = otpConfiguration["hotp"] self.totpConfiguration = otpConfiguration["totp"] hmacShaAlgorithm = self.totpConfiguration["hmacShaAlgorithm"] hmacShaAlgorithmType = None if StringHelper.equalsIgnoreCase(hmacShaAlgorithm, "sha1"): hmacShaAlgorithmType = HmacShaAlgorithm.HMAC_SHA_1 elif StringHelper.equalsIgnoreCase(hmacShaAlgorithm, "sha256"): hmacShaAlgorithmType = HmacShaAlgorithm.HMAC_SHA_256 elif StringHelper.equalsIgnoreCase(hmacShaAlgorithm, "sha512"): hmacShaAlgorithmType = HmacShaAlgorithm.HMAC_SHA_512 else: print "OTP. Load OTP configuration. Invalid TOTP HMAC SHA algorithm: '%s'" % hmacShaAlgorithm self.totpConfiguration["hmacShaAlgorithmType"] = hmacShaAlgorithmType except: print "OTP. Load OTP configuration. Invalid configuration file '%s' format. Exception: '%s'" % (otp_conf_file, sys.exc_info()[1]) return False return True
def validateSessionId(self, identity): session_id = CdiUtil.bean(SessionIdService).getSessionIdFromCookie() if StringHelper.isEmpty(session_id): print "OTP. Validate session id. Failed to determine session_id" return False otp_auth_method = identity.getWorkingParameter("otp_auth_method") if not otp_auth_method in ['enroll', 'authenticate']: print "OTP. Validate session id. Failed to authenticate user. otp_auth_method: '%s'" % otp_auth_method return False return True
def authenticate(self, configurationAttributes, requestParameters, step): authenticationService = CdiUtil.bean(AuthenticationService) if (step == 1): print "Basic. Authenticate for step 1" identity = CdiUtil.bean(Identity) credentials = identity.getCredentials() user_name = credentials.getUsername() user_password = credentials.getPassword() logged_in = False if (StringHelper.isNotEmptyString(user_name) and StringHelper.isNotEmptyString(user_password)): logged_in = authenticationService.authenticate(user_name, user_password) if (not logged_in): return False return True else: return False
def isInboundJwt(self, value): if value == None: return False try: jwt = Jwt.parse(value) user_profile_json = jwt.getClaims().getClaimAsString("data") if StringHelper.isEmpty(user_profile_json): return False except: return False return True
def prepareForStep(self, configurationAttributes, requestParameters, step): identity = CdiUtil.bean(Identity) if (step == 1): return True elif (step == 2): print "Fido2. Prepare for step 2" session_id = CdiUtil.bean(SessionIdService).getSessionIdFromCookie() if StringHelper.isEmpty(session_id): print "Fido2. Prepare for step 2. Failed to determine session_id" return False authenticationService = CdiUtil.bean(AuthenticationService) user = authenticationService.getAuthenticatedUser() if (user == None): print "Fido2. Prepare for step 2. Failed to determine user name" return False userName = user.getUserId() metaDataConfiguration = self.getMetaDataConfiguration() # Check if user have registered devices registrationPersistenceService = CdiUtil.bean(RegistrationPersistenceService) assertionResponse = None attestationResponse = None userFido2Devices = registrationPersistenceService.findAllRegisteredByUsername(userName) if (userFido2Devices.size() > 0): print "Fido2. Prepare for step 2. Call Fido2 endpoint in order to start assertion flow" try: assertionService = Fido2ClientFactory.instance().createAssertionService(metaDataConfiguration) assertionRequest = json.dumps({'username': userName}, separators=(',', ':')) assertionResponse = assertionService.authenticate(assertionRequest).readEntity(java.lang.String) except ClientResponseFailure, ex: print "Fido2. Prepare for step 2. Failed to start assertion flow. Exception:", sys.exc_info()[1] return False else: print "Fido2. Prepare for step 2. Call Fido2 endpoint in order to start attestation flow" try: attestationService = Fido2ClientFactory.instance().createAttestationService(metaDataConfiguration) attestationRequest = json.dumps({'username': userName, 'displayName': userName}, separators=(',', ':')) attestationResponse = attestationService.register(attestationRequest).readEntity(java.lang.String) except ClientResponseFailure, ex: print "Fido2. Prepare for step 2. Failed to start attestation flow. Exception:", sys.exc_info()[1] return False
def prepareForStep(self, configurationAttributes, requestParameters, step): identity = CdiUtil.bean(Identity) if (step == 1): return True elif (step == 2): print "U2F. Prepare for step 2" session_id = CdiUtil.bean(SessionIdService).getSessionIdFromCookie() if StringHelper.isEmpty(session_id): print "U2F. Prepare for step 2. Failed to determine session_id" return False authenticationService = CdiUtil.bean(AuthenticationService) user = authenticationService.getAuthenticatedUser() if (user == None): print "U2F. Prepare for step 2. Failed to determine user name" return False u2f_application_id = configurationAttributes.get("u2f_application_id").getValue2() # Check if user have registered devices deviceRegistrationService = CdiUtil.bean(DeviceRegistrationService) userInum = user.getAttribute("inum") registrationRequest = None authenticationRequest = None deviceRegistrations = deviceRegistrationService.findUserDeviceRegistrations(userInum, u2f_application_id) if (deviceRegistrations.size() > 0): print "U2F. Prepare for step 2. Call FIDO U2F in order to start authentication workflow" try: authenticationRequestService = FidoU2fClientFactory.instance().createAuthenticationRequestService(self.metaDataConfiguration) authenticationRequest = authenticationRequestService.startAuthentication(user.getUserId(), None, u2f_application_id, session_id) except ClientResponseFailure, ex: if (ex.getResponse().getResponseStatus() != Response.Status.NOT_FOUND): print "U2F. Prepare for step 2. Failed to start authentication workflow. Exception:", sys.exc_info()[1] return False else: print "U2F. Prepare for step 2. Call FIDO U2F in order to start registration workflow" registrationRequestService = FidoU2fClientFactory.instance().createRegistrationRequestService(self.metaDataConfiguration) registrationRequest = registrationRequestService.startRegistration(user.getUserId(), u2f_application_id, session_id) identity.setWorkingParameter("fido_u2f_authentication_request", ServerUtil.asJson(authenticationRequest)) identity.setWorkingParameter("fido_u2f_registration_request", ServerUtil.asJson(registrationRequest)) return True
def getCustomAuthzParameter(self, simpleCustProperty): customAuthzParameter = None if simpleCustProperty != None: prop = simpleCustProperty.getValue2() if StringHelper.isNotEmpty(prop): customAuthzParameter = prop if customAuthzParameter == None: print "Passport. getCustomAuthzParameter. No custom param for OIDC authz request in script properties" print "Passport. getCustomAuthzParameter. Passport flow cannot be initiated by doing an OpenID connect authorization request" else: print "Passport. getCustomAuthzParameter. Custom param for OIDC authz request in script properties: %s" % customAuthzParameter return customAuthzParameter
def prepareClientsSet(self, configurationAttributes): clientsSet = HashSet() if (not configurationAttributes.containsKey("allowed_clients")): return clientsSet allowedClientsList = configurationAttributes.get("allowed_clients").getValue2() if (StringHelper.isEmpty(allowedClientsList)): print "UMA authorization policy. Initialization. The property allowed_clients is empty" return clientsSet allowedClientsListArray = StringHelper.split(allowedClientsList, ",") if (ArrayHelper.isEmpty(allowedClientsListArray)): print "UMA authorization policy. Initialization. There aren't clients specified in allowed_clients property" return clientsSet # Convert to HashSet to quick search i = 0 count = len(allowedClientsListArray) while (i < count): client = allowedClientsListArray[i] clientsSet.add(client) i = i + 1 return clientsSet
def authorize(self, context): # context is reference of org.gluu.oxauth.uma.authorization.UmaAuthorizationContext print "RPT Policy. Authorizing ..." client_id=context.getClient().getClientId() print "UmaRptPolicy. client_id = %s" % client_id if (StringHelper.isEmpty(client_id)): return False if (self.clientsSet.contains(client_id)): print "UmaRptPolicy. Authorizing client" return True else: print "UmaRptPolicy. Client isn't authorized" return False
def prepareForStep(self, configurationAttributes, requestParameters, step): if REMOTE_DEBUG: pydevd.settrace('localhost', port=5678, stdoutToServer=True, stderrToServer=True) # Inject dependencies identity = CdiUtil.bean(Identity) facesResources = CdiUtil.bean(FacesResources) facesService = CdiUtil.bean(FacesService) userService = CdiUtil.bean(UserService) session = identity.getSessionId() sessionAttributes = session.getSessionAttributes() externalContext = facesResources.getFacesContext().getExternalContext() uiLocales = sessionAttributes.get(AuthorizeRequestParam.UI_LOCALES) rpConfig = self.getRPConfig(session) clientUri = self.getClientUri(session) externalContext.addResponseHeader( "Content-Security-Policy", "default-src 'self' https://www.canada.ca; font-src 'self' https://fonts.gstatic.com https://use.fontawesome.com https://www.canada.ca; style-src 'self' 'unsafe-inline'; style-src-elem 'self' 'unsafe-inline' https://use.fontawesome.com https://fonts.googleapis.com https://www.canada.ca; script-src 'self' 'unsafe-inline' https://www.canada.ca https://ajax.googleapis.com; connect-src 'self' https://*.fjgc-gccf.gc.ca" ) if step == 1: httpRequest = externalContext.getRequest() # Bookmark detection #if httpRequest.getHeader("referer") is None: # if StringHelper.isNotEmpty(clientUri): # facesService.redirectToExternalURL(clientUri) # return True # else: # print("%s: prepareForStep. clientUri is missing for client %s" % (self.name, self.getClient(session).getClientName())) # return False # forceAuthn workaround prompt2 = httpRequest.getParameter("prompt2") if prompt2 == "login": identity.setWorkingParameter("forceAuthn", True) # step could actually be 2, or 3 if uiLocales is not None: if len(self.providers) > 1: step = self.STEP_CHOOSER else: step = self.STEP_1FA if identity.getWorkingParameter("abort"): # Back button workaround # Obtain the client URI of the current client from the client configuration if len(self.providers ) == 1: # Pass through, so send them back to the client if StringHelper.isNotEmpty(clientUri): facesService.redirectToExternalURL(clientUri) return True else: print( "%s: prepareForStep. clientUri is missing for client %s" % (self.name, self.getClient(session).getClientName())) return False else: # reset the chooser identity.setWorkingParameter("provider", None) if step == self.STEP_CHOOSER: # Prepare for chooser page customization. for param in ["layout", "chooser", "content"]: identity.setWorkingParameter(param, rpConfig[param]) elif step in {self.STEP_1FA, self.STEP_COLLECT, self.STEP_2FA}: # Passport passportOptions = { "ui_locales": uiLocales, "exp": int(time.time()) + 60 } if step in {self.STEP_1FA, self.STEP_COLLECT}: provider = identity.getWorkingParameter("provider") if provider is None and len( self.providers ) == 1: # Only one provider. Direct Pass-through provider = next(iter(self.providers)) identity.setWorkingParameter("provider", provider) if step == self.STEP_1FA: # Coordinate single-sign-on (SSO) maxAge = (sessionAttributes.get(AuthorizeRequestParam.MAX_AGE) or self.getClient(session).getDefaultMaxAge()) if (identity.getWorkingParameter("forceAuthn") or ("GCCF" in self.passport.getProvider(provider)["options"] and maxAge < 1200) ): # 1200 is 20 minutes, the SSO timeout on GCKey and CBS passportOptions["forceAuthn"] = "true" elif step == self.STEP_COLLECT: collect = rpConfig.get("collect") if collect is not None: passportOptions["allowCreate"] = rpConfig.get( "allowCreate") or "false" passportOptions["spNameQualifier"] = collect else: # This should never happen print( "%s. prepareForStep: collection entityID is missing" % self.name) return False elif step == self.STEP_2FA: provider = rpConfig.get("mfaProvider") if provider is None: print("%s: prepareForStep. mfaProvider is missing!" % self.name) return False mfaId = identity.getWorkingParameter("mfaId") if mfaId is None: print("%s: prepareForStep. mfaId is missing!" % self.name) return False else: passportOptions["login_hint"] = mfaId # The following parameters are redundant, but currently required by the 2ndFaaS passportOptions[ "redirect_uri"] = self.passport.getProvider( provider)["callbackUrl"] passportOptions["response_type"] = "code" passportOptions["scope"] = "openid profile" # Set the abort flag to handle back button identity.setWorkingParameter("abort", True) # Send the request to passport passportRequest = self.passport.createRequest( provider, passportOptions) facesService.redirectToExternalURL(passportRequest) elif step in {self.STEP_FIDO_REGISTER, self.STEP_FIDO_AUTH}: userId = identity.getWorkingParameter("userId") metaDataConfiguration = self.getFidoMetaDataConfiguration() if step == self.STEP_FIDO_REGISTER: try: attestationService = Fido2ClientFactory.instance( ).createAttestationService(metaDataConfiguration) attestationRequest = json.dumps( { 'username': userId, 'displayName': userId, 'attestation': 'direct', 'timeout': 120000, 'userVerification': 'discouraged' }, separators=(',', ':')) attestationResponse = attestationService.register( attestationRequest).readEntity(java.lang.String) except ClientErrorException as ex: print( "%s. Prepare for step. Failed to start FIDO2 attestation flow. Exception:" % self.name, sys.exc_info()[1]) return False identity.setWorkingParameter( "fido2_attestation_request", ServerUtil.asJson(attestationResponse)) print(ServerUtil.asJson(attestationResponse)) elif step == self.STEP_FIDO_AUTH: userId = identity.getWorkingParameter("userId") metaDataConfiguration = self.getFidoMetaDataConfiguration() fidoDeviceCount = userService.countFidoAndFido2Devices( userId, self.fido2_domain) try: assertionService = Fido2ClientFactory.instance( ).createAssertionService(metaDataConfiguration) assertionRequest = json.dumps( { 'username': userId, 'timeout': 120000, 'userVerification': 'discouraged' }, separators=(',', ':')) assertionResponse = assertionService.authenticate( assertionRequest).readEntity(java.lang.String) except ClientErrorException as ex: print( "%s. Prepare for step. Failed to start FIDO2 assertion flow. Exception:" % self.name, sys.exc_info()[1]) return False identity.setWorkingParameter( "fido2_assertion_request", ServerUtil.asJson(assertionResponse)) return True
def authenticate(self, configurationAttributes, requestParameters, step): extensionResult = self.extensionAuthenticate(configurationAttributes, requestParameters, step) if extensionResult != None: return extensionResult print "Passport. authenticate for step %s called" % str(step) identity = CdiUtil.bean(Identity) if step == 1: jwt_param = None if self.isInboundFlow(identity): print "Passport. authenticate for step 1. Detected idp-initiated inbound Saml flow" jwt_param = identity.getSessionId().getSessionAttributes().get( AuthorizeRequestParam.STATE) if jwt_param == None: jwt_param = ServerUtil.getFirstValue(requestParameters, "user") if jwt_param != None: print "Passport. authenticate for step 1. JWT user profile token found" # Parse JWT and validate jwt = Jwt.parse(jwt_param) if not self.validSignature(jwt): return False if self.jwtHasExpired(jwt): return False (user_profile, jsonp) = self.getUserProfile(jwt) if user_profile == None: return False return self.attemptAuthentication(identity, user_profile, jsonp) #See passportlogin.xhtml provider = ServerUtil.getFirstValue(requestParameters, "loginForm:provider") if StringHelper.isEmpty(provider): #it's username + passw auth print "Passport. authenticate for step 1. Basic authentication detected" logged_in = False credentials = identity.getCredentials() user_name = credentials.getUsername() user_password = credentials.getPassword() if StringHelper.isNotEmptyString( user_name) and StringHelper.isNotEmptyString( user_password): authenticationService = CdiUtil.bean(AuthenticationService) logged_in = authenticationService.authenticate( user_name, user_password) print "Passport. authenticate for step 1. Basic authentication returned: %s" % logged_in return logged_in elif provider in self.registeredProviders: #it's a recognized external IDP identity.setWorkingParameter("selectedProvider", provider) print "Passport. authenticate for step 1. Retrying step 1" #see prepareForStep (step = 1) return True if step == 2: mail = ServerUtil.getFirstValue(requestParameters, "loginForm:email") jsonp = identity.getWorkingParameter("passport_user_profile") if mail == None: self.setMessageError(FacesMessage.SEVERITY_ERROR, "Email was missing in user profile") elif jsonp != None: # Completion of profile takes place user_profile = json.loads(jsonp) user_profile["mail"] = mail return self.attemptAuthentication(identity, user_profile, jsonp) print "Passport. authenticate for step 2. Failed: expected mail value in HTTP request and json profile in session" return False
def authenticate(self, configurationAttributes, requestParameters, step): identity = CdiUtil.bean(Identity) credentials = identity.getCredentials() userService = CdiUtil.bean(UserService) requestParameterService = CdiUtil.bean(RequestParameterService) authenticationService = CdiUtil.bean(AuthenticationService) httpService = CdiUtil.bean(HttpService) if step == 1: print "CAS2. Authenticate for step 1" ticket_array = requestParameters.get("ticket") if ArrayHelper.isEmpty(ticket_array): print "CAS2. Authenticate for step 1. ticket is empty" return False ticket = ticket_array[0] print "CAS2. Authenticate for step 1. ticket: " + ticket if StringHelper.isEmptyString(ticket): print "CAS2. Authenticate for step 1. ticket is invalid" return False # Validate ticket facesContext = CdiUtil.bean(FacesContext) request = facesContext.getExternalContext().getRequest() parametersMap = HashMap() parametersMap.put("service", httpService.constructServerUrl(request) + "/postlogin.htm") if self.cas_renew_opt: parametersMap.put("renew", "true") parametersMap.put("ticket", ticket) cas_service_request_uri = requestParameterService.parametersAsString(parametersMap) cas_service_request_uri = self.cas_host + "/serviceValidate?" + cas_service_request_uri if self.cas_extra_opts != None: cas_service_request_uri = cas_service_request_uri + "&" + self.cas_extra_opts print "CAS2. Authenticate for step 1. cas_service_request_uri: " + cas_service_request_uri http_client = httpService.getHttpsClient() http_service_response = httpService.executeGet(http_client, cas_service_request_uri) try: validation_content = httpService.convertEntityToString(httpService.getResponseContent(http_service_response.getHttpResponse())) finally: http_service_response.closeConnection() print "CAS2. Authenticate for step 1. validation_content: " + validation_content if StringHelper.isEmpty(validation_content): print "CAS2. Authenticate for step 1. Ticket validation response is invalid" return False cas2_auth_failure = self.parse_tag(validation_content, "cas:authenticationFailure") print "CAS2. Authenticate for step 1. cas2_auth_failure: ", cas2_auth_failure cas2_user_uid = self.parse_tag(validation_content, "cas:user") print "CAS2. Authenticate for step 1. cas2_user_uid: ", cas2_user_uid if (cas2_auth_failure != None) or (cas2_user_uid == None): print "CAS2. Authenticate for step 1. Ticket is invalid" return False if self.cas_map_user: print "CAS2. Authenticate for step 1. Attempting to find user by oxExternalUid: cas2:" + cas2_user_uid # Check if the is user with specified cas2_user_uid find_user_by_uid = userService.getUserByAttribute("oxExternalUid", "cas2:" + cas2_user_uid) if find_user_by_uid == None: print "CAS2. Authenticate for step 1. Failed to find user" print "CAS2. Authenticate for step 1. Setting count steps to 2" identity.setWorkingParameter("cas2_count_login_steps", 2) identity.setWorkingParameter("cas2_user_uid", cas2_user_uid) return True found_user_name = find_user_by_uid.getUserId() print "CAS2. Authenticate for step 1. found_user_name: " + found_user_name authenticationService.authenticate(found_user_name) print "CAS2. Authenticate for step 1. Setting count steps to 1" identity.setWorkingParameter("cas2_count_login_steps", 1) return True else: print "CAS2. Authenticate for step 1. Attempting to find user by uid:" + cas2_user_uid # Check if there is user with specified cas2_user_uid find_user_by_uid = userService.getUser(cas2_user_uid) if find_user_by_uid == None: print "CAS2. Authenticate for step 1. Failed to find user" return False found_user_name = find_user_by_uid.getUserId() print "CAS2. Authenticate for step 1. found_user_name: " + found_user_name authenticationService.authenticate(found_user_name) print "CAS2. Authenticate for step 1. Setting count steps to 1" identity.setWorkingParameter("cas2_count_login_steps", 1) return True elif step == 2: print "CAS2. Authenticate for step 2" if identity.isSetWorkingParameter("cas2_user_uid"): print "CAS2. Authenticate for step 2. cas2_user_uid is empty" return False cas2_user_uid = identity.getWorkingParameter("cas2_user_uid") passed_step1 = StringHelper.isNotEmptyString(cas2_user_uid) if not passed_step1: return False user_name = credentials.getUsername() user_password = credentials.getPassword() logged_in = False if StringHelper.isNotEmptyString(user_name) and StringHelper.isNotEmptyString(user_password): logged_in = authenticationService.authenticate(user_name, user_password) if not logged_in: return False # Check if there is user which has cas2_user_uid # Avoid mapping CAS2 account to more than one IDP account find_user_by_uid = userService.getUserByAttribute("oxExternalUid", "cas2:" + cas2_user_uid) if find_user_by_uid == None: # Add cas2_user_uid to user one id UIDs find_user_by_uid = userService.addUserAttribute(user_name, "oxExternalUid", "cas2:" + cas2_user_uid) if find_user_by_uid == None: print "CAS2. Authenticate for step 2. Failed to update current user" return False return True else: found_user_name = find_user_by_uid.getUserId() print "CAS2. Authenticate for step 2. found_user_name: " + found_user_name if StringHelper.equals(user_name, found_user_name): return True return False else: return False
def authenticate(self, configurationAttributes, requestParameters, step): identity = CdiUtil.bean(Identity) userService = CdiUtil.bean(UserService) authenticationService = CdiUtil.bean(AuthenticationService) mapUserDeployment = False enrollUserDeployment = False if (configurationAttributes.containsKey("gplus_deployment_type")): deploymentType = StringHelper.toLowerCase(configurationAttributes.get("gplus_deployment_type").getValue2()) if (StringHelper.equalsIgnoreCase(deploymentType, "map")): mapUserDeployment = True if (StringHelper.equalsIgnoreCase(deploymentType, "enroll")): enrollUserDeployment = True if (step == 1): print "Google+ Authenticate for step 1" gplusAuthCodeArray = requestParameters.get("gplus_auth_code") gplusAuthCode = gplusAuthCodeArray[0] # Check if user uses basic method to log in useBasicAuth = False if (StringHelper.isEmptyString(gplusAuthCode)): useBasicAuth = True # Use basic method to log in if (useBasicAuth): print "Google+ Authenticate for step 1. Basic authentication" identity.setWorkingParameter("gplus_count_login_steps", 1) credentials = identity.getCredentials() userName = credentials.getUsername() userPassword = credentials.getPassword() loggedIn = False if (StringHelper.isNotEmptyString(userName) and StringHelper.isNotEmptyString(userPassword)): userService = CdiUtil.bean(UserService) loggedIn = authenticationService.authenticate(userName, userPassword) if (not loggedIn): return False return True # Use Google+ method to log in print "Google+ Authenticate for step 1. gplusAuthCode:", gplusAuthCode currentClientSecrets = self.getCurrentClientSecrets(self.clientSecrets, configurationAttributes, requestParameters) if (currentClientSecrets == None): print "Google+ Authenticate for step 1. Client secrets configuration is invalid" return False print "Google+ Authenticate for step 1. Attempting to gets tokens" tokenResponse = self.getTokensByCode(self.clientSecrets, configurationAttributes, gplusAuthCode) if ((tokenResponse == None) or (tokenResponse.getIdToken() == None) or (tokenResponse.getAccessToken() == None)): print "Google+ Authenticate for step 1. Failed to get tokens" return False else: print "Google+ Authenticate for step 1. Successfully gets tokens" jwt = Jwt.parse(tokenResponse.getIdToken()) # TODO: Validate ID Token Signature gplusUserUid = jwt.getClaims().getClaimAsString(JwtClaimName.SUBJECT_IDENTIFIER) print "Google+ Authenticate for step 1. Found Google user ID in the ID token: '%s'" % gplusUserUid if (mapUserDeployment): # Use mapping to local IDP user print "Google+ Authenticate for step 1. Attempting to find user by oxExternalUid: 'gplus:%s'" % gplusUserUid # Check if there is user with specified gplusUserUid foundUser = userService.getUserByAttribute("oxExternalUid", "gplus:" + gplusUserUid) if (foundUser == None): print "Google+ Authenticate for step 1. Failed to find user" print "Google+ Authenticate for step 1. Setting count steps to 2" identity.setWorkingParameter("gplus_count_login_steps", 2) identity.setWorkingParameter("gplus_user_uid", gplusUserUid) return True foundUserName = foundUser.getUserId() print "Google+ Authenticate for step 1. foundUserName: '******'" % foundUserName userAuthenticated = authenticationService.authenticate(foundUserName) if (userAuthenticated == False): print "Google+ Authenticate for step 1. Failed to authenticate user" return False print "Google+ Authenticate for step 1. Setting count steps to 1" identity.setWorkingParameter("gplus_count_login_steps", 1) postLoginResult = self.extensionPostLogin(configurationAttributes, foundUser) print "Google+ Authenticate for step 1. postLoginResult: '%s'" % postLoginResult return postLoginResult elif (enrollUserDeployment): # Use auto enrollment to local IDP print "Google+ Authenticate for step 1. Attempting to find user by oxExternalUid: 'gplus:%s'" % gplusUserUid # Check if there is user with specified gplusUserUid foundUser = userService.getUserByAttribute("oxExternalUid", "gplus:" + gplusUserUid) if (foundUser == None): # Auto user enrollemnt print "Google+ Authenticate for step 1. There is no user in LDAP. Adding user to local LDAP" print "Google+ Authenticate for step 1. Attempting to gets user info" userInfoResponse = self.getUserInfo(currentClientSecrets, configurationAttributes, tokenResponse.getAccessToken()) if ((userInfoResponse == None) or (userInfoResponse.getClaims().size() == 0)): print "Google+ Authenticate for step 1. Failed to get user info" return False else: print "Google+ Authenticate for step 1. Successfully gets user info" gplusResponseAttributes = userInfoResponse.getClaims() # Convert Google+ user claims to lover case gplusResponseNormalizedAttributes = HashMap() for gplusResponseAttributeEntry in gplusResponseAttributes.entrySet(): gplusResponseNormalizedAttributes.put( StringHelper.toLowerCase(gplusResponseAttributeEntry.getKey()), gplusResponseAttributeEntry.getValue()) currentAttributesMapping = self.getCurrentAttributesMapping(self.attributesMapping, configurationAttributes, requestParameters) print "Google+ Authenticate for step 1. Using next attributes mapping '%s'" % currentAttributesMapping newUser = User() for attributesMappingEntry in currentAttributesMapping.entrySet(): remoteAttribute = attributesMappingEntry.getKey() localAttribute = attributesMappingEntry.getValue() localAttributeValue = gplusResponseNormalizedAttributes.get(remoteAttribute) if (localAttribute != None): newUser.setAttribute(localAttribute, localAttributeValue) if (newUser.getAttribute("sn") == None): newUser.setAttribute("sn", gplusUserUid) if (newUser.getAttribute("cn") == None): newUser.setAttribute("cn", gplusUserUid) # Add mail to oxTrustEmail so that the user's # email is available through the SCIM interface # too. if (newUser.getAttribute("oxTrustEmail") is None and newUser.getAttribute("mail") is not None): oxTrustEmail = { "value": newUser.getAttribute("mail"), "display": newUser.getAttribute("mail"), "primary": True, "operation": None, "reference": None, "type": "other" } newUser.setAttribute("oxTrustEmail", json.dumps(oxTrustEmail)) newUser.setAttribute("oxExternalUid", "gplus:" + gplusUserUid) print "Google+ Authenticate for step 1. Attempting to add user '%s' with next attributes '%s'" % (gplusUserUid, newUser.getCustomAttributes()) foundUser = userService.addUser(newUser, True) print "Google+ Authenticate for step 1. Added new user with UID: '%s'" % foundUser.getUserId() foundUserName = foundUser.getUserId() print "Google+ Authenticate for step 1. foundUserName: '******'" % foundUserName userAuthenticated = authenticationService.authenticate(foundUserName) if (userAuthenticated == False): print "Google+ Authenticate for step 1. Failed to authenticate user" return False print "Google+ Authenticate for step 1. Setting count steps to 1" identity.setWorkingParameter("gplus_count_login_steps", 1) print "Google+ Authenticate for step 1. Attempting to run extension postLogin" postLoginResult = self.extensionPostLogin(configurationAttributes, foundUser) print "Google+ Authenticate for step 1. postLoginResult: '%s'" % postLoginResult return postLoginResult else: # Check if there is user with specified gplusUserUid print "Google+ Authenticate for step 1. Attempting to find user by uid: '%s'" % gplusUserUid foundUser = userService.getUser(gplusUserUid) if (foundUser == None): print "Google+ Authenticate for step 1. Failed to find user" return False foundUserName = foundUser.getUserId() print "Google+ Authenticate for step 1. foundUserName: '******'" % foundUserName userAuthenticated = authenticationService.authenticate(foundUserName) if (userAuthenticated == False): print "Google+ Authenticate for step 1. Failed to authenticate user" return False print "Google+ Authenticate for step 1. Setting count steps to 1" identity.setWorkingParameter("gplus_count_login_steps", 1) postLoginResult = self.extensionPostLogin(configurationAttributes, foundUser) print "Google+ Authenticate for step 1. postLoginResult: '%s'" % postLoginResult return postLoginResult elif (step == 2): print "Google+ Authenticate for step 2" sessionAttributes = identity.getSessionId().getSessionAttributes() if (sessionAttributes == None) or not sessionAttributes.containsKey("gplus_user_uid"): print "Google+ Authenticate for step 2. gplus_user_uid is empty" return False gplusUserUid = sessionAttributes.get("gplus_user_uid") passed_step1 = StringHelper.isNotEmptyString(gplusUserUid) if (not passed_step1): return False identity = CdiUtil.bean(Identity) credentials = identity.getCredentials() userName = credentials.getUsername() userPassword = credentials.getPassword() loggedIn = False if (StringHelper.isNotEmptyString(userName) and StringHelper.isNotEmptyString(userPassword)): loggedIn = authenticationService.authenticate(userName, userPassword) if (not loggedIn): return False # Check if there is user which has gplusUserUid # Avoid mapping Google account to more than one IDP account foundUser = userService.getUserByAttribute("oxExternalUid", "gplus:" + gplusUserUid) if (foundUser == None): # Add gplusUserUid to user one id UIDs foundUser = userService.addUserAttribute(userName, "oxExternalUid", "gplus:" + gplusUserUid) if (foundUser == None): print "Google+ Authenticate for step 2. Failed to update current user" return False postLoginResult = self.extensionPostLogin(configurationAttributes, foundUser) print "Google+ Authenticate for step 2. postLoginResult: '%s'" % postLoginResult return postLoginResult else: foundUserName = foundUser.getUserId() print "Google+ Authenticate for step 2. foundUserName: '******'" % foundUserName if StringHelper.equals(userName, foundUserName): postLoginResult = self.extensionPostLogin(configurationAttributes, foundUser) print "Google+ Authenticate for step 2. postLoginResult: '%s'" % postLoginResult return postLoginResult return False else: return False
def processOtpAuthentication(self, requestParameters, user_name, identity, otp_auth_method): facesMessages = CdiUtil.bean(FacesMessages) facesMessages.setKeepMessages() userService = CdiUtil.bean(UserService) otpCode = ServerUtil.getFirstValue(requestParameters, "loginForm:otpCode") if StringHelper.isEmpty(otpCode): facesMessages.add(FacesMessage.SEVERITY_ERROR, "Failed to authenticate. OTP code is empty") print "OTP. Process OTP authentication. otpCode is empty" return False if otp_auth_method == "enroll": # Get key from session otp_secret_key_encoded = identity.getWorkingParameter( "otp_secret_key") if otp_secret_key_encoded == None: print "OTP. Process OTP authentication. OTP secret key is invalid" return False otp_secret_key = self.fromBase64Url(otp_secret_key_encoded) if self.otpType == "hotp": validation_result = self.validateHotpKey( otp_secret_key, 1, otpCode) if (validation_result != None) and validation_result["result"]: print "OTP. Process HOTP authentication during enrollment. otpCode is valid" # Store HOTP Secret Key and moving factor in user entry otp_user_external_uid = "hotp:%s;%s" % ( otp_secret_key_encoded, validation_result["movingFactor"]) # Add otp_user_external_uid to user's external GUID list find_user_by_external_uid = userService.addUserAttribute( user_name, "oxExternalUid", otp_user_external_uid) if find_user_by_external_uid != None: return True print "OTP. Process HOTP authentication during enrollment. Failed to update user entry" elif self.otpType == "totp": validation_result = self.validateTotpKey( otp_secret_key, otpCode) if (validation_result != None) and validation_result["result"]: print "OTP. Process TOTP authentication during enrollment. otpCode is valid" # Store TOTP Secret Key and moving factor in user entry otp_user_external_uid = "totp:%s" % otp_secret_key_encoded # Add otp_user_external_uid to user's external GUID list find_user_by_external_uid = userService.addUserAttribute( user_name, "oxExternalUid", otp_user_external_uid) if find_user_by_external_uid != None: return True print "OTP. Process TOTP authentication during enrollment. Failed to update user entry" elif otp_auth_method == "authenticate": # Modified for Casa compliance user_enrollments = self.findEnrollments(user_name, "hotp") #if len(user_enrollments) == 0: # print "OTP. Process OTP authentication. There is no OTP enrollment for user '%s'" % user_name # facesMessages.add(FacesMessage.SEVERITY_ERROR, "There is no valid OTP user enrollments") # return False if len(user_enrollments) > 0: for user_enrollment in user_enrollments: user_enrollment_data = user_enrollment.split(";") otp_secret_key_encoded = user_enrollment_data[0] # Get current moving factor from user entry moving_factor = StringHelper.toInteger( user_enrollment_data[1]) otp_secret_key = self.fromBase64Url(otp_secret_key_encoded) # Validate TOTP validation_result = self.validateHotpKey( otp_secret_key, moving_factor, otpCode) if (validation_result != None) and validation_result["result"]: print "OTP. Process HOTP authentication during authentication. otpCode is valid" otp_user_external_uid = "hotp:%s;%s" % ( otp_secret_key_encoded, moving_factor) new_otp_user_external_uid = "hotp:%s;%s" % ( otp_secret_key_encoded, validation_result["movingFactor"]) # Update moving factor in user entry find_user_by_external_uid = userService.replaceUserAttribute( user_name, "oxExternalUid", otp_user_external_uid, new_otp_user_external_uid) if find_user_by_external_uid != None: return True print "OTP. Process HOTP authentication during authentication. Failed to update user entry" user_enrollments = self.findEnrollments(user_name, "totp") if len(user_enrollments) > 0: for user_enrollment in user_enrollments: otp_secret_key = self.fromBase64Url(user_enrollment) # Validate TOTP validation_result = self.validateTotpKey( otp_secret_key, otpCode) if (validation_result != None) and validation_result["result"]: print "OTP. Process TOTP authentication during authentication. otpCode is valid" return True facesMessages.add(FacesMessage.SEVERITY_ERROR, "Failed to authenticate. OTP code is invalid") print "OTP. Process OTP authentication. OTP code is invalid" return False
def containsAttributeString(self, dictionary, attribute): return ((attribute in dictionary) and StringHelper.isNotEmptyString(dictionary[attribute]))
def authenticate(self, configurationAttributes, requestParameters, step): userService = CdiUtil.bean(UserService) authenticationService = CdiUtil.bean(AuthenticationService) facesMessages = CdiUtil.bean(FacesMessages) facesMessages.setKeepMessages() session_attributes = self.identity.getSessionId().getSessionAttributes( ) form_passcode = ServerUtil.getFirstValue(requestParameters, "passcode") print("SMPP form_response_passcode: {}".format(str(form_passcode))) if step == 1: print("SMPP Step 1 Password Authentication") credentials = self.identity.getCredentials() user_name = credentials.getUsername() user_password = credentials.getPassword() logged_in = False if StringHelper.isNotEmptyString( user_name) and StringHelper.isNotEmptyString( user_password): logged_in = authenticationService.authenticate( user_name, user_password) if not logged_in: return False # Get the Person's number and generate a code foundUser = None try: foundUser = authenticationService.getAuthenticatedUser() except: print("SMPP Error retrieving user {} from LDAP".format( user_name)) return False mobile_number = None try: isVerified = foundUser.getAttribute("phoneNumberVerified") if isVerified: mobile_number = foundUser.getAttribute("employeeNumber") if not mobile_number: mobile_number = foundUser.getAttribute("mobile") if not mobile_number: mobile_number = foundUser.getAttribute("telephoneNumber") if not mobile_number: facesMessages.add( FacesMessage.SEVERITY_ERROR, "Failed to determine mobile phone number") print("SMPP Error finding mobile number for user '{}'". format(user_name)) return False except Exception as e: facesMessages.add(FacesMessage.SEVERITY_ERROR, "Failed to determine mobile phone number") print("SMPP Error finding mobile number for {}: {}".format( user_name, e)) return False # Generate Random six digit code code = random.randint(100000, 999999) # Get code and save it in LDAP temporarily with special session entry self.identity.setWorkingParameter("code", code) self.identity.setWorkingParameter("mobile_number", mobile_number) self.identity.getSessionId().getSessionAttributes().put( "mobile_number", mobile_number) if not self.sendMessage(mobile_number, str(code)): facesMessages.add(FacesMessage.SEVERITY_ERROR, "Failed to send message to mobile phone") return False return True elif step == 2: # Retrieve the session attribute print("SMPP Step 2 SMS/OTP Authentication") code = session_attributes.get("code") print("SMPP Code: {}".format(str(code))) if code is None: print("SMPP Failed to find previously sent code") return False if form_passcode is None: print("SMPP Passcode is empty") return False if len(form_passcode) != 6: print("SMPP Passcode from response is not 6 digits: {}".format( form_passcode)) return False if form_passcode == code: print("SMPP SUCCESS! User entered the same code!") return True print("SMPP failed, user entered the wrong code! {} != {}".format( form_passcode, code)) facesMessages.add(facesMessage.SEVERITY_ERROR, "Incorrect SMS code, please try again.") return False print("SMPP ERROR: step param not found or != (1|2)") return False
def prepareForStep(self, configurationAttributes, requestParameters, step): extensionResult = self.extensionPrepareForStep(configurationAttributes, requestParameters, step) if extensionResult != None: return extensionResult print "Passport. prepareForStep called %s" % str(step) identity = CdiUtil.bean(Identity) if step == 1: #re-read the strategies config (for instance to know which strategies have enabled the email account linking) self.parseProviderConfigs() identity.setWorkingParameter("externalProviders", json.dumps(self.registeredProviders)) providerParam = self.customAuthzParameter url = None sessionAttributes = identity.getSessionId().getSessionAttributes() self.skipProfileUpdate = StringHelper.equalsIgnoreCase( sessionAttributes.get("skipPassportProfileUpdate"), "true") #this param could have been set previously in authenticate step if current step is being retried provider = identity.getWorkingParameter("selectedProvider") print "prepareForStep %s - provider = %s" % (str(step), str(provider)) # if there is a selectedProvider if provider != None: # get the redirect URL to use at facesService.redirectToExternalURL() that sends /passport/auth/<provider>/<token> url = self.getPassportRedirectUrl(provider) print "prepareForStep %s - url = %s" % (str(step), url) # sets selectedProvider back to None identity.setWorkingParameter("selectedProvider", None) # if there is customAuthzParameter elif providerParam != None: # get it from sessionAtributes paramValue = sessionAttributes.get(providerParam) #if exists if paramValue != None: print "Passport. prepareForStep. Found value in custom param of authorization request: %s" % paramValue provider = self.getProviderFromJson(paramValue) if provider == None: print "Passport. prepareForStep. A provider value could not be extracted from custom authorization request parameter" elif not provider in self.registeredProviders: print "Passport. prepareForStep. Provider '%s' not part of known configured IDPs/OPs" % provider else: url = self.getPassportRedirectUrl(provider) # if no provider selected yet... if url == None: print "Passport. prepareForStep. A page to manually select an identity provider will be shown" # else already got the /passport/auth/<provider>/<token> url... else: facesService = CdiUtil.bean(FacesService) # redirects to Passport getRedirectURL - sends browser to IDP. print "Passport. Redirecting to external url: %s" + url facesService.redirectToExternalURL(url) return True
def isPassedDefaultAuthentication(self): identity = CdiUtil.bean(Identity) credentials = identity.getCredentials() user_name = credentials.getUsername() passed_step1 = StringHelper.isNotEmptyString(user_name) return passed_step1
def authenticate(self, configurationAttributes, requestParameters, step): identity = CdiUtil.bean(Identity) userService = CdiUtil.bean(UserService) authenticationService = CdiUtil.bean(AuthenticationService) httpService = CdiUtil.bean(HttpService) server_flag = configurationAttributes.get( "oneid_server_flag").getValue2() callback_attrs = configurationAttributes.get( "oneid_callback_attrs").getValue2() creds_file = configurationAttributes.get( "oneid_creds_file").getValue2() # Create OneID authn = OneID(server_flag) # Set path to credentials file authn.creds_file = creds_file if (step == 1): print "OneId. Authenticate for step 1" # Find OneID request json_data_array = requestParameters.get("json_data") if ArrayHelper.isEmpty(json_data_array): print "OneId. Authenticate for step 1. json_data is empty" return False request = json_data_array[0] print "OneId. Authenticate for step 1. request: " + request if (StringHelper.isEmptyString(request)): return False authn.set_credentials() # Validate request http_client = httpService.getHttpsClientDefaulTrustStore() auth_data = httpService.encodeBase64(authn.api_id + ":" + authn.api_key) http_response = httpService.executePost( http_client, authn.helper_server + "/validate", auth_data, request, ContentType.APPLICATION_JSON) validation_content = httpService.convertEntityToString( httpService.getResponseContent(http_response)) print "OneId. Authenticate for step 1. validation_content: " + validation_content if (StringHelper.isEmptyString(validation_content)): return False validation_resp = json.loads(validation_content) print "OneId. Authenticate for step 1. validation_resp: " + str( validation_resp) if (not authn.success(validation_resp)): return False response = json.loads(request) for x in validation_resp: response[x] = validation_resp[x] oneid_user_uid = response['uid'] print "OneId. Authenticate for step 1. oneid_user_uid: " + oneid_user_uid # Check if the is user with specified oneid_user_uid find_user_by_uid = userService.getUserByAttribute( "oxExternalUid", "oneid:" + oneid_user_uid) if (find_user_by_uid == None): print "OneId. Authenticate for step 1. Failed to find user" print "OneId. Authenticate for step 1. Setting count steps to 2" identity.setWorkingParameter("oneid_count_login_steps", 2) identity.setWorkingParameter("oneid_user_uid", oneid_user_uid) return True found_user_name = find_user_by_uid.getUserId() print "OneId. Authenticate for step 1. found_user_name: " + found_user_name identity = CdiUtil.bean(Identity) credentials = identity.getCredentials() credentials.setUsername(found_user_name) credentials.setUser(find_user_by_uid) print "OneId. Authenticate for step 1. Setting count steps to 1" identity.setWorkingParameter("oneid_count_login_steps", 1) return True elif (step == 2): print "OneId. Authenticate for step 2" sessionAttributes = identity.getSessionId().getSessionAttributes() if (sessionAttributes == None ) or not sessionAttributes.containsKey("oneid_user_uid"): print "OneId. Authenticate for step 2. oneid_user_uid is empty" return False oneid_user_uid = sessionAttributes.get("oneid_user_uid") passed_step1 = StringHelper.isNotEmptyString(oneid_user_uid) if (not passed_step1): return False identity = CdiUtil.bean(Identity) credentials = identity.getCredentials() user_name = credentials.getUsername() passed_step1 = StringHelper.isNotEmptyString(user_name) if (not passed_step1): return False identity = CdiUtil.bean(Identity) credentials = identity.getCredentials() user_name = credentials.getUsername() user_password = credentials.getPassword() logged_in = False if (StringHelper.isNotEmptyString(user_name) and StringHelper.isNotEmptyString(user_password)): logged_in = authenticationService.authenticate( user_name, user_password) if (not logged_in): return False # Check if there is user which has oneid_user_uid # Avoid mapping OneID account to more than one IDP account find_user_by_uid = userService.getUserByAttribute( "oxExternalUid", "oneid:" + oneid_user_uid) if (find_user_by_uid == None): # Add oneid_user_uid to user one id UIDs find_user_by_uid = userService.addUserAttribute( user_name, "oxExternalUid", "oneid:" + oneid_user_uid) if (find_user_by_uid == None): print "OneId. Authenticate for step 2. Failed to update current user" return False return True else: found_user_name = find_user_by_uid.getUserId() print "OneId. Authenticate for step 2. found_user_name: " + found_user_name if StringHelper.equals(user_name, found_user_name): return True return False else: return False
def authenticate(self, configurationAttributes, requestParameters, step): identity = CdiUtil.bean(Identity) credentials = identity.getCredentials() session_attributes = identity.getSessionId().getSessionAttributes() self.setRequestScopedParameters(identity) if (step == 1): print "UAF. Authenticate for step 1" user_name = credentials.getUsername() authenticated_user = self.processBasicAuthentication(credentials) if authenticated_user == None: return False uaf_auth_method = "authenticate" # Uncomment this block if you need to allow user second device registration #enrollment_mode = ServerUtil.getFirstValue(requestParameters, "loginForm:registerButton") #if StringHelper.isNotEmpty(enrollment_mode): # uaf_auth_method = "enroll" if uaf_auth_method == "authenticate": user_enrollments = self.findEnrollments(credentials) if len(user_enrollments) == 0: uaf_auth_method = "enroll" print "UAF. Authenticate for step 1. There is no UAF enrollment for user '%s'. Changing uaf_auth_method to '%s'" % (user_name, uaf_auth_method) print "UAF. Authenticate for step 1. uaf_auth_method: '%s'" % uaf_auth_method identity.setWorkingParameter("uaf_auth_method", uaf_auth_method) return True elif (step == 2): print "UAF. Authenticate for step 2" session_id = CdiUtil.bean(SessionIdService).getSessionIdFromCookie() if StringHelper.isEmpty(session_id): print "UAF. Prepare for step 2. Failed to determine session_id" return False user = authenticationService.getAuthenticatedUser() if (user == None): print "UAF. Authenticate for step 2. Failed to determine user name" return False user_name = user.getUserId() uaf_auth_result = ServerUtil.getFirstValue(requestParameters, "auth_result") if uaf_auth_result != "success": print "UAF. Authenticate for step 2. auth_result is '%s'" % uaf_auth_result return False # Restore state from session uaf_auth_method = session_attributes.get("uaf_auth_method") if not uaf_auth_method in ['enroll', 'authenticate']: print "UAF. Authenticate for step 2. Failed to authenticate user. uaf_auth_method: '%s'" % uaf_auth_method return False # Request STATUS_OBB if True: #TODO: Remove this condition # It's workaround becuase it's not possible to call STATUS_OBB 2 times. First time on browser and second ime on server uaf_user_device_handle = ServerUtil.getFirstValue(requestParameters, "auth_handle") else: uaf_obb_auth_method = session_attributes.get("uaf_obb_auth_method") uaf_obb_server_uri = session_attributes.get("uaf_obb_server_uri") uaf_obb_start_response = session_attributes.get("uaf_obb_start_response") # Prepare STATUS_OBB uaf_obb_start_response_json = json.loads(uaf_obb_start_response) uaf_obb_status_request_dictionary = { "operation": "STATUS_%s" % uaf_obb_auth_method, "userName": user_name, "needDetails": 1, "oobStatusHandle": uaf_obb_start_response_json["oobStatusHandle"], } uaf_obb_status_request = json.dumps(uaf_obb_status_request_dictionary, separators=(',',':')) print "UAF. Authenticate for step 2. Prepared STATUS request: '%s' to send to '%s'" % (uaf_obb_status_request, uaf_obb_server_uri) uaf_status_obb_response = self.executePost(uaf_obb_server_uri, uaf_obb_status_request) if uaf_status_obb_response == None: return False print "UAF. Authenticate for step 2. Get STATUS response: '%s'" % uaf_status_obb_response uaf_status_obb_response_json = json.loads(uaf_status_obb_response) if uaf_status_obb_response_json["statusCode"] != 4000: print "UAF. Authenticate for step 2. UAF operation status is invalid. statusCode: '%s'" % uaf_status_obb_response_json["statusCode"] return False uaf_user_device_handle = uaf_status_obb_response_json["additionalInfo"]["authenticatorsResult"]["handle"] if StringHelper.isEmpty(uaf_user_device_handle): print "UAF. Prepare for step 2. Failed to get UAF handle" return False uaf_user_external_uid = "uaf:%s" % uaf_user_device_handle print "UAF. Authenticate for step 2. UAF handle: '%s'" % uaf_user_external_uid if uaf_auth_method == "authenticate": # Validate if user used device with same keYHandle user_enrollments = self.findEnrollments(credentials) if len(user_enrollments) == 0: uaf_auth_method = "enroll" print "UAF. Authenticate for step 2. There is no UAF enrollment for user '%s'." % user_name return False for user_enrollment in user_enrollments: if StringHelper.equalsIgnoreCase(user_enrollment, uaf_user_device_handle): print "UAF. Authenticate for step 2. There is UAF enrollment for user '%s'. User authenticated successfully" % user_name return True else: userService = CdiUtil.bean(UserService) # Double check just to make sure. We did checking in previous step # Check if there is user which has uaf_user_external_uid # Avoid mapping user cert to more than one IDP account find_user_by_external_uid = userService.getUserByAttribute("oxExternalUid", uaf_user_external_uid) if find_user_by_external_uid == None: # Add uaf_user_external_uid to user's external GUID list find_user_by_external_uid = userService.addUserAttribute(user_name, "oxExternalUid", uaf_user_external_uid) if find_user_by_external_uid == None: print "UAF. Authenticate for step 2. Failed to update current user" return False return True return False else: return False
def authenticate(self, configurationAttributes, requestParameters, step): print "IDP Chooser. authenticate called for step '%s'" % step identity = CdiUtil.bean(Identity) sessionId = identity.getSessionId() sessionAttributes = sessionId.getSessionAttributes() # SWITCH - if the switch credential is in 3_DO_SWITCH state, then do the switch if (sessionAttributes.get("switchFlowStatus") == "3_DO_SWITCH"): # first get the target user userService = CdiUtil.bean(UserService) sourceUser = userService.getUser( sessionAttributes.get("switchSourceAuthenticatedUser")) targetUser = userService.getUser( sessionAttributes.get("switchTargetAuthenticatedUser")) if (targetUser == None): print "IDP Chooser. authenticate: Failed to fetch target user '%s'" % sessionAttributes.get( "switchTargetAuthenticatedUser") sessionAttributes.remove("switchFlowStatus") ## SESSION_SAFE - update CdiUtil.bean(SessionIdService).updateSessionId(sessionId) return False elif (sourceUser == None): print "IDP Chooser. authenticate: Failed to fetch source user '%s'" % sessionAttributes.get( "switchSourceAuthenticatedUser") sessionAttributes.remove("switchFlowStatus") ## SESSION_SAFE - update CdiUtil.bean(SessionIdService).updateSessionId(sessionId) return False else: switchPersistentId = sessionAttributes.get( "switchPersistentId") # FIRST set the persistentId for the entitySpNameQualifier in the target user tergetPersistentIds = targetUser.getAttributeValues( "persistentId") tmpList = ArrayList( tergetPersistentIds ) if tergetPersistentIds != None else ArrayList() tmpList.add(switchPersistentId) targetUser.setAttribute("persistentId", tmpList) userService.updateUser(targetUser) # SECOND remove the persistentId for the entitySpNameQualifier in the source user sourcePersistentIds = sourceUser.getAttributeValues( "persistentId") tmpList = ArrayList() # build a new list of persistentIds without the switched ID for sourcePersistentId in sourcePersistentIds: if (sourcePersistentId != switchPersistentId): tmpList.add( sessionAttributes.get("switchPersistentId")) sourceUser.setAttribute("persistentId", tmpList) try: userService.updateUser(sourceUser) except: # THIRD if failed to update the source then reset the source user print "IDP Chooser. authenticate: Failed to update source user, '%s', reverting target user " % sessionAttributes.get( "switchSourceAuthenticatedUser") print "Exception: ", sys.exc_info()[1] tergetPersistentIds = targetUser.getAttributeValues( "persistentId") tmpList = ArrayList( tergetPersistentIds ) if tergetPersistentIds != None else ArrayList() tmpList.add(sessionAttributes.get("switchPersistentId")) targetUser.setAttribute("persistentId", tmpList) userService.updateUser(targetUser) return False # finish the switch flow sessionAttributes.put("switchFlowStatus", "4_FINISHED") ## SESSION_SAFE - update return CdiUtil.bean(AuthenticationService).authenticate( targetUser.getUserId()) else: # process the ACR selection new_acr_provider_value = self.getAcrValueFromAuth( requestParameters) print "IDP Chooser. authenticate: saving new acr provider = '%s'" % new_acr_provider_value new_acr_provider_elements = StringHelper.split( new_acr_provider_value, ":") new_acr_value = new_acr_provider_elements[0] new_acr_provider = new_acr_provider_elements[1] print "IDP Chooser. authenticate: setting new_acr_value = '%s'" % new_acr_value print "IDP Chooser. authenticate: setting new_acr_provider = '%s'" % new_acr_provider # Validate the ACR is allowed for the current entityId/client allowedCredentials = sessionAttributes.get( "pageContent")["credentials"] allowSetNewAcr = False for cred in StringHelper.split(allowedCredentials, ','): if (new_acr_provider_value.find(cred) == -1): allowSetNewAcr = True if (allowSetNewAcr): identity.setWorkingParameter("new_acr_value", new_acr_value) sessionAttributes.put("selectedProvider", new_acr_provider) else: print "IDP Chooser. authenticate: provider '%s' not allowed for this client" % new_acr_provider return False # SWITCH - Reading switch credential checkbox switchFlowStatus = sessionAttributes.get("switchFlowStatus") if (switchFlowStatus == None): switchSelected = self.getSwitchValueFromAuth(requestParameters) if (switchSelected == True): print "IDP Chooser. authenticate SWITCH FLOW: setting 1_GET_SOURCE" sessionAttributes.put("switchFlowStatus", "1_GET_SOURCE") ## SESSION_SAFE - update CdiUtil.bean(SessionIdService).updateSessionId(sessionId) if step == 1: return True else: return False
def authenticate(self, configurationAttributes, requestParameters, step): print("SMPP Authenticate for step {}".format(step)) identity = CdiUtil.bean(Identity) authenticationService = CdiUtil.bean(AuthenticationService) user = authenticationService.getAuthenticatedUser() if step == 1: if not user: credentials = identity.getCredentials() user_name = credentials.getUsername() user_password = credentials.getPassword() if StringHelper.isNotEmptyString( user_name) and StringHelper.isNotEmptyString( user_password): authenticationService.authenticate(user_name, user_password) user = authenticationService.getAuthenticatedUser() if not user: return False numbers = self.getNumbers(user) if not numbers: return False else: # Generate Random six digit code code = random.randint(100000, 999999) identity.setWorkingParameter("randCode", code) if len(numbers) == 1: return self.sendMessage(numbers[0], str(code)) else: chopped = [number[-4:] for number in numbers] # converting to comma-separated list (identity does not remember lists) identity.setWorkingParameter("numbers", ",".join(numbers)) identity.setWorkingParameter("choppedNos", ",".join(chopped)) return True else: if not user: return False session_attributes = identity.getSessionId().getSessionAttributes() code = session_attributes.get("randCode") numbers = session_attributes.get("numbers") if step == 2 and numbers: # Means that the selection number page was used idx = ServerUtil.getFirstValue( requestParameters, "OtpSmsloginForm:indexOfNumber") if idx and code: number = numbers.split(",")[int(idx)] return self.sendMessage(number, str(code)) else: return False form_passcode = ServerUtil.getFirstValue( requestParameters, "OtpSmsloginForm:passcode") if form_passcode and code == form_passcode: print( "SMPP authenticate. 6-digit code matches with code sent via SMS" ) return True else: facesMessages = CdiUtil.bean(FacesMessages) facesMessages.setKeepMessages() facesMessages.clear() facesMessages.add(FacesMessage.SEVERITY_ERROR, "Wrong code entered") return False
def prepareForStep(self, configurationAttributes, requestParameters, step): print "IDP Chooser. prepareForStep called for step '%s'" % step identity = CdiUtil.bean(Identity) sessionId = identity.getSessionId() sessionAttributes = sessionId.getSessionAttributes() entityId = sessionAttributes.get("entityId") entitySpNameQualifier = sessionAttributes.get("spNameQualifier") # entityId is used for UI branding. Handle getting entityId if it's an OIDC client if (entityId == None): # First get the client_id (should be deterministic ... ?????) currentClientId = sessionAttributes.get("client_id") # Call the ClientService and get all clients clientService = CdiUtil.bean(ClientService) oidcClient = clientService.getClient(currentClientId) if (oidcClient != None): entityId = "oidc:%s" % oidcClient.getClientName() sessionAttributes.put("entityId", entityId) # SpNameQualifier is used for persistenId generation. Handle getting entitySpNameQualifier if it's an OIDC client if (entitySpNameQualifier == None): # Look for value saved in the PolicyURL field in the client configurationAttributes clientPolicyUri = oidcClient.getPolicyUri() if (StringHelper.isNotEmpty(clientPolicyUri)): # Set it to the clientPolicyUri if absent entitySpNameQualifier = clientPolicyUri sessionAttributes.put("spNameQualifier", clientPolicyUri) # FIXME - For now as an error scenario if it's not found put a default if (entityId == None): entityId = "_default" # CUSTOMIZATION - Select which page body elements will be rendered if (sessionAttributes.get("pageContent") == None): # CUSTOMIZATION - FIRST try direct match pageContent = self.selectorPageContent.get(entityId) # CUSTOMIZATION - SECOND try prefix match if (pageContent == None): for contentKey in self.selectorPageContent.keys(): if (entityId.find(contentKey) == 0): pageContent = self.selectorPageContent.get(contentKey) # CUSTOMIZATION - LASTLY go to default content if (pageContent == None): pageContent = self.selectorPageContent.get("_default") # CUSTOMIZATION - save the page content in session for reference in xhtml pages if (pageContent != None): sessionAttributes.put("pageContent", pageContent) else: # We have an error - log it and fail print "IDP Chooser. prepareForStep ERROR: '_default' and '%s' page content missing in file " % ( entityId, configurationAttributes.get( "selector_page_content_file").getValue2()) return False # CUSTOMIZATION - Select which credential buttons will show up showCredentials = sessionAttributes.get( "pageContent")["credentials"] allCredentials = self.selectorPageContent["_default"][ "credentials"] for cred in StringHelper.split(allCredentials, ','): if (showCredentials.find(cred) == -1): sessionAttributes.put("hide_cred_" + cred, False) # SWITCH - update switch flow step if coming back with a user if (sessionAttributes.get("switchFlowStatus") == "1_GET_SOURCE" and sessionAttributes.get("auth_user") != None): # first get the source user and validate the persistentId exists for the entitySpNameQualifier userService = CdiUtil.bean(UserService) sourceUser = userService.getUser( sessionAttributes.get("switchSourceAuthenticatedUser")) # then find the persistenId for the entitySpNameQualifier in the source user sourcePersistentIds = sourceUser.getAttributeValues("persistentId") if (sourcePersistentIds != None): # go through source user persistentIds for userPersistentId in sourcePersistentIds: existingMappedRp = StringHelper.split( userPersistentId, '|')[0] # if the current RP matches, save the persistenId for the target if (userPersistentId.find(entitySpNameQualifier) > -1): sessionAttributes.put("switchPersistentId", userPersistentId) print "IDP Chooser. prepareForStep SWITCH FLOW: setting 2_GET_TARGET" sessionAttributes.put("switchFlowStatus", "2_GET_TARGET") # SWITCH - move to switch screen if the target has been authenticated elif (sessionAttributes.get("switchFlowStatus") == "2_GET_TARGET" and sessionAttributes.get("auth_user") != None): # first get the target user userService = CdiUtil.bean(UserService) targetUser = userService.getUser( sessionAttributes.get("switchTargetAuthenticatedUser")) # then find the persistenId for the entitySpNameQualifier in the target user targetPersistentIds = targetUser.getAttributeValues("persistentId") switchCurrentState = "AVAILABLE" if (targetPersistentIds != None): # go through source user persistentIds for userPersistentId in targetPersistentIds: existingMappedRp = StringHelper.split( userPersistentId, '|')[0] # if the current RP already has a persistentId then mark it if (entitySpNameQualifier != None and userPersistentId.find(entitySpNameQualifier) > -1): switchCurrentState = "NOT AVAILABLE - Persistent ID already exists for this RP in the target" if (switchCurrentState == "AVAILABLE"): print "IDP Chooser. prepareForStep SWITCH FLOW: setting 3_DO_SWITCH" sessionAttributes.put("switchFlowStatus", "3_DO_SWITCH") else: print "IDP Chooser. prepareForStep SWITCH FLOW: FAILED - target contains mapping for %s" % entitySpNameQualifier sessionAttributes.put("switchFlowStatus", "4_FINISHED") sessionAttributes.put("switchCurrentState", switchCurrentState) # MFA - update mfa flow status - check if the entityId is on the list of MFA applications mfaFlowStatus = sessionAttributes.get("mfaFlowStatus") print "IDP Chooser. prepareForStep Fetched mfaFlowStatus = '%s'" % mfaFlowStatus for mfaEntityId in StringHelper.split(self.entityids_with_mfa, ','): if (mfaEntityId == entityId): # if the status is blank then we set it to MFA_1_REQUIRED. This also means first pass so no MFA forwarding if (mfaFlowStatus == None): mfaFlowStatus = "MFA_1_REQUIRED" print "IDP Chooser. prepareForStep Setting mfaFlowStatus = '%s'" % mfaFlowStatus sessionAttributes.put("mfaFlowStatus", mfaFlowStatus) # we check that we have an authenticated user, which is a signal to trigger MFA elif (sessionAttributes.get("auth_user") != None): print "IDP Chooser. prepareForStep For mfaFlowStatus found authenticated user = '******'" % sessionAttributes.get( "auth_user") # SWITCH - we check that we are not in a switch flow, or switch flow has finished switchFlowStatus = sessionAttributes.get( "switchSourceAuthenticatedUser") if (switchFlowStatus == None or switchFlowStatus == "4_FINISHED"): mfaFlowStatus = "MFA_2_IN_PROGRESS" print "IDP Chooser. prepareForStep Setting mfaFlowStatus = '%s' and [new_acr_value to 'passport_social'] and [selectedProvider to 'mfa']" % mfaFlowStatus sessionAttributes.put("mfaFlowStatus", mfaFlowStatus) print "IDP Chooser. prepareForStep Setting [new_acr_value = 'passport_social'] and [selectedProvider = 'mfa']" identity.setWorkingParameter("new_acr_value", "passport_social") sessionAttributes.put("selectedProvider", "mfa") ## SESSION_SAFE - update CdiUtil.bean(SessionIdService).updateSessionId(sessionId) print "IDP Chooser. prepareForStep. got session '%s'" % identity.getSessionId( ).toString() if (step == 1 or step == 2): return True else: return False
def validateTotpKey(self, secretKey, totpKey): localTotpKey = self.generateTotpKey(secretKey) if StringHelper.equals(localTotpKey, totpKey): return {"result": True} return {"result": False}
def checkStatus(self, iw_api_uri, iw_service_id, user_name, session_id, without_pin): print "inside check status ", user_name + session_id # step 1: call action=pushAthenticate httpService = CdiUtil.bean(HttpService) request_uri = iw_api_uri + "action=pushAuthenticate" + "&serviceId=" + str( iw_service_id) + "&userId=" + httpService.encodeUrl( user_name) + "&format=json&withoutpin=" + str(without_pin) #curTime = java.lang.System.currentTimeMillis() #endTime = curTime + (timeout * 1000) try: response_status = None http_service_response = httpService.executeGet( self.client, request_uri) http_response = http_service_response.getHttpResponse() if (http_response.getStatusLine().getStatusCode() != 200): print "inWebo. Invalid response from inwebo server: checkStatus ", str( http_response.getStatusLine().getStatusCode()) httpService.consume(http_response) return None response_bytes = httpService.getResponseContent(http_response) response_string = httpService.convertEntityToString(response_bytes) httpService.consume(http_response) except: print "inWebo validate method. Exception: ", sys.exc_info()[1] return False finally: http_service_response.closeConnection() print "response string:", response_string json_response = json.loads(response_string) if StringHelper.equalsIgnoreCase(json_response['err'], "OK"): session_id = json_response['sessionId'] checkResult_uri = iw_api_uri + "action=checkPushResult" + "&serviceId=" + str( iw_service_id) + "&userId=" + httpService.encodeUrl( user_name) + "&sessionId=" + httpService.encodeUrl( session_id) + "&format=json&withoutpin=1" print "checkPushResult_uri:", checkResult_uri startTime = System.currentTimeMillis() currentTime = startTime endTime = startTime + long(25000) print "start time ----> ", startTime print "end time ", endTime while (endTime > currentTime): try: # step 2: call action=checkPushResult; using session id from step 1 http_check_push_response = httpService.executeGet( self.client, checkResult_uri) check_push_response = http_check_push_response.getHttpResponse( ) check_push_response_bytes = httpService.getResponseContent( check_push_response) check_push_response_string = httpService.convertEntityToString( check_push_response_bytes) httpService.consume(check_push_response) check_push_json_response = json.loads( check_push_response_string) print "check_push_json_response :", check_push_json_response if StringHelper.equalsIgnoreCase( check_push_json_response['err'], "OK"): self.push_fail = None return True elif StringHelper.equalsIgnoreCase( check_push_json_response['err'], "NOK:REFUSED"): print "Push request notification for session", session_id self.push_fail = "inwebo.push.notification.rejected" return False elif StringHelper.equalsIgnoreCase( check_push_json_response['err'], "NOK:TIMEOUT"): print "Push request timed out for session", session_id self.push_fail = "inwebo.push.notification.timed.out.for.session" return False elif StringHelper.equalsIgnoreCase( check_push_json_response['err'], "NOK:WAITING"): self.push_fail = "inwebo.push.notification.timed.out.for.session" currentTime = System.currentTimeMillis() print " NOw ######## ", currentTime java.lang.Thread.sleep(5000) continue else: self.push_fail = "inwebo.push.notification.failed" return False finally: http_check_push_response.closeConnection() elif StringHelper.equalsIgnoreCase(json_response['err'], "NOK:SN"): self.push_fail = "inwebo.no.username" return False elif StringHelper.equalsIgnoreCase(json_response['err'], "NOK:account unknown"): self.push_fail = "inwebo.no.username" return False else: print "No response from server." self.push_fail = "inwebo.push.notification.timed.out.for.session" return False print "inWebo. CheckStatus. The process has not received a response from the phone yet" return False
def bindWWPass(self, requestParameters, userService, authenticationService, identity, ticket): puid = identity.getWorkingParameter("puid") email = requestParameters.get('email')[0] if 'email' in requestParameters else None if not puid: identity.setWorkingParameter("errors", "WWPass login failed") return False if ticket: puid_new = self.getPuid(ticket) # Always use the latest PUID when retrying step 2 identity.setWorkingParameter("puid", puid_new) if puid == puid_new: # Registering via external web service if not self.registration_url: return False if self.tryFirstLogin(puid, userService, authenticationService): identity.setWorkingParameter("puid", None) return True else: if not self.allow_passkey_bind: return False # Binding with existing PassKey user = userService.getUserByAttribute("oxExternalUid", "wwpass:%s"%puid_new) if user: if authenticationService.authenticate(user.getUserId()): userService.addUserAttribute(user.getUserId(), "oxExternalUid", "wwpass:%s"%puid) identity.setWorkingParameter("puid", None) return True identity.setWorkingParameter("errors", "Invalid user") return False elif email: # Binding via email if not self.allow_email_bind: return False email = requestParameters.get('email')[0] if 'email' in requestParameters else None identity.setWorkingParameter("email", email) user = userService.getUserByAttribute('mail', email) if not user: print("User with email '%s' not found." % email) return True nonce = self.generateNonce(33) mailService = CdiUtil.bean(MailService) identity.setWorkingParameter("email_nonce", nonce) identity.setWorkingParameter("email_nonce_exp", str(time() + self.EMAIL_NONCE_EXPIRATION)) subject = "Bind your WWPass Key" body = """ To bind your WWPass Key to your account, copy and paste the following code into "Email code" field in the login form: %s If you haven't requested this operation, you can safely disregard this email. """ mailService.sendMail(email, subject, body % nonce) return True else: # Binding via username/password if not self.allow_password_bind: return False puid = identity.getWorkingParameter("puid") if not puid: return False credentials = identity.getCredentials() user_name = credentials.getUsername() user_password = credentials.getPassword() logged_in = False if (StringHelper.isNotEmptyString(user_name) and StringHelper.isNotEmptyString(user_password)): try: logged_in = authenticationService.authenticate(user_name, user_password) except Exception as e: print(e) if not logged_in: identity.setWorkingParameter("errors", "Invalid username or password") return False user = authenticationService.getAuthenticatedUser() if not user: identity.setWorkingParameter("errors", "Invalid user") return False userService.addUserAttribute(user_name, "oxExternalUid", "wwpass:%s"%puid) identity.setWorkingParameter("puid", None) return True return False
def authenticate(self, configurationAttributes, requestParameters, step): authenticationService = CdiUtil.bean(AuthenticationService) identity = CdiUtil.bean(Identity) credentials = identity.getCredentials() self.setRequestScopedParameters(identity) if step == 1: print "OTP. Authenticate for step 1" # Modified for Casa compliance authenticated_user = authenticationService.getAuthenticatedUser() if authenticated_user == None: authenticated_user = self.processBasicAuthentication( credentials) if authenticated_user == None: return False otp_auth_method = "authenticate" # Uncomment this block if you need to allow user second OTP registration #enrollment_mode = ServerUtil.getFirstValue(requestParameters, "loginForm:registerButton") #if StringHelper.isNotEmpty(enrollment_mode): # otp_auth_method = "enroll" # Modified for Casa compliance if not self.hasEnrollments(configurationAttributes, authenticated_user): return False #if otp_auth_method == "authenticate": # user_enrollments = self.findEnrollments(authenticated_user.getUserId()) # if len(user_enrollments) == 0: # otp_auth_method = "enroll" # print "OTP. Authenticate for step 1. There is no OTP enrollment for user '%s'. Changing otp_auth_method to '%s'" % (authenticated_user.getUserId(), otp_auth_method) if otp_auth_method == "enroll": print "OTP. Authenticate for step 1. Setting count steps: '%s'" % 3 identity.setWorkingParameter("otp_count_login_steps", 3) print "OTP. Authenticate for step 1. otp_auth_method: '%s'" % otp_auth_method identity.setWorkingParameter("otp_auth_method", otp_auth_method) return True elif step == 2: print "OTP. Authenticate for step 2" authenticationService = CdiUtil.bean(AuthenticationService) user = authenticationService.getAuthenticatedUser() if user == None: print "OTP. Authenticate for step 2. Failed to determine user name" return False session_id_validation = self.validateSessionId(identity) if not session_id_validation: return False # Restore state from session otp_auth_method = identity.getWorkingParameter("otp_auth_method") if otp_auth_method == 'enroll': auth_result = ServerUtil.getFirstValue(requestParameters, "auth_result") if not StringHelper.isEmpty(auth_result): print "OTP. Authenticate for step 2. User not enrolled OTP" return False print "OTP. Authenticate for step 2. Skipping this step during enrollment" return True otp_auth_result = self.processOtpAuthentication( requestParameters, user.getUserId(), identity, otp_auth_method) print "OTP. Authenticate for step 2. OTP authentication result: '%s'" % otp_auth_result return otp_auth_result elif step == 3: print "OTP. Authenticate for step 3" authenticationService = CdiUtil.bean(AuthenticationService) user = authenticationService.getAuthenticatedUser() if user == None: print "OTP. Authenticate for step 2. Failed to determine user name" return False session_id_validation = self.validateSessionId(identity) if not session_id_validation: return False # Restore state from session otp_auth_method = identity.getWorkingParameter("otp_auth_method") if otp_auth_method != 'enroll': return False otp_auth_result = self.processOtpAuthentication( requestParameters, user.getUserId(), identity, otp_auth_method) print "OTP. Authenticate for step 3. OTP authentication result: '%s'" % otp_auth_result return otp_auth_result else: return False
def authenticate(self, configurationAttributes, requestParameters, step): print "Casa. authenticate %s" % str(step) userService = CdiUtil.bean(UserService) authenticationService = CdiUtil.bean(AuthenticationService) identity = CdiUtil.bean(Identity) if step == 1: 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) mfaOff = foundUser.getAttribute( "oxPreferredMethod") == None logged_in = False if mfaOff: logged_in = authenticationService.authenticate( user_name, user_password) else: acr = self.getSuitableAcr(foundUser, platform_data) 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("oxTrustedDevicesInfo", tdi) userService.updateUser(user) else: print "Casa. authenticate. 2FA authentication failed" return success return False
def prepareForStep(self, configurationAttributes, requestParameters, step): authenticationService = CdiUtil.bean(AuthenticationService) identity = CdiUtil.bean(Identity) credentials = identity.getCredentials() session_attributes = identity.getSessionId().getSessionAttributes() self.setRequestScopedParameters(identity) if (step == 1): return True elif (step == 2): print "UAF. Prepare for step 2" session_id = CdiUtil.bean(SessionIdService).getSessionIdFromCookie() if StringHelper.isEmpty(session_id): print "UAF. Prepare for step 2. Failed to determine session_id" return False user = authenticationService.getAuthenticatedUser() if (user == None): print "UAF. Prepare for step 2. Failed to determine user name" return False uaf_auth_method = session_attributes.get("uaf_auth_method") if StringHelper.isEmpty(uaf_auth_method): print "UAF. Prepare for step 2. Failed to determine auth_method" return False print "UAF. Prepare for step 2. uaf_auth_method: '%s'" % uaf_auth_method uaf_obb_auth_method = "OOB_REG" uaf_obb_server_uri = self.uaf_server_uri + "/nnl/v2/reg" if StringHelper.equalsIgnoreCase(uaf_auth_method, "authenticate"): uaf_obb_auth_method = "OOB_AUTH" uaf_obb_server_uri = self.uaf_server_uri + "/nnl/v2/auth" # Prepare START_OBB uaf_obb_start_request_dictionary = { "operation": "START_%s" % uaf_obb_auth_method, "userName": user.getUserId(), "policyName": "default", "oobMode": { "qr": "true", "rawData": "false", "push": "false" } } uaf_obb_start_request = json.dumps(uaf_obb_start_request_dictionary, separators=(',',':')) print "UAF. Prepare for step 2. Prepared START request: '%s' to send to '%s'" % (uaf_obb_start_request, uaf_obb_server_uri) # Request START_OBB uaf_obb_start_response = self.executePost(uaf_obb_server_uri, uaf_obb_start_request) if uaf_obb_start_response == None: return False print "UAF. Prepare for step 2. Get START response: '%s'" % uaf_obb_start_response uaf_obb_start_response_json = json.loads(uaf_obb_start_response) # Prepare STATUS_OBB #TODO: Remove needDetails parameter uaf_obb_status_request_dictionary = { "operation": "STATUS_%s" % uaf_obb_auth_method, "userName": user.getUserId(), "needDetails": 1, "oobStatusHandle": uaf_obb_start_response_json["oobStatusHandle"], } uaf_obb_status_request = json.dumps(uaf_obb_status_request_dictionary, separators=(',',':')) print "UAF. Prepare for step 2. Prepared STATUS request: '%s' to send to '%s'" % (uaf_obb_status_request, uaf_obb_server_uri) identity.setWorkingParameter("uaf_obb_auth_method", uaf_obb_auth_method) identity.setWorkingParameter("uaf_obb_server_uri", uaf_obb_server_uri) identity.setWorkingParameter("uaf_obb_start_response", uaf_obb_start_response) identity.setWorkingParameter("qr_image", uaf_obb_start_response_json["modeResult"]["qrCode"]["qrImage"]) identity.setWorkingParameter("uaf_obb_status_request", uaf_obb_status_request) return True else: return False
def update(self, dynamicScopeContext, configurationAttributes): print ("Dynamic scope [claims_scope]. Update method") # Get the client and session and dynamic claims authorizationGrant = dynamicScopeContext.getAuthorizationGrant() oidcClient = authorizationGrant.getClient() currentEntityId = "oidc:%s" % oidcClient.getClientName() # sessionDn = authorizationGrant.getSessionDn() # print "Dynamic scope [claims_scope]. Got session DN = '%s'" % sessionDn # sessionId = dynamicScopeContext.getEntryAttributeValue(sessionDn, "sessionId") # if ( sessionDn != None ): # prepare the search results attributes claimNamesJsonString = None claimsSrcJsonString = None # then we look for the SAML persistentId value in user profile user = dynamicScopeContext.getUser() userTransientIds = user.getAttributeValues("transientId") if ( userTransientIds != None ): if ( userTransientIds.size > 0 ): # save latest time (set to 0 initially) latestExpiryTimeSec = 0 # go through existing user persistentIds for userTransientId in userTransientIds: # if the current RP already has a mapping then skip the second phase transientIdRp = StringHelper.split(userTransientId,'|')[0] if ( transientIdRp == currentEntityId ): print ("Dynamic scope [claims_scope]. Found matching transientId '%s'" % userTransientId) # Format is : currentOidcRp, expiryTimeSec, userInfoUrl, accessToken expiryTimeSec = StringHelper.split(userTransientId,'|')[1] userInfoUrl = StringHelper.split(userTransientId,'|')[2] accessToken = StringHelper.split(userTransientId,'|')[3] # Check the last timestamp is newer than the current one and not older than 15 minutes (900 second) expiryTimeSec = StringHelper.toInteger(expiryTimeSec) currenttimeSec = int(round(time.time())) if ( expiryTimeSec > latestExpiryTimeSec and expiryTimeSec > (currenttimeSec - 900) ): # Save expiry and update/set the _claim_sources parameters latestExpiryTimeSec = expiryTimeSec # create a JSON object with _claim_sources for distributed claims claimsSrcJsonString = '{"src1":{"endpoint":"%s","access_token":"%s"}}' % ( userInfoUrl, accessToken ) # Set the _claim_names value to the result - static as per PCTF ####################################################### # "_claim_names": { # "given_name": "src1", # "family_name": "src1", # "birthdate": "src1", # "address": "src1" # }, # create a JSON object with _claim_sources for distributed claims claimNamesJsonString = '{"given_name":"src1","family_name":"src1","birthdate":"src1","address":"src1"}' # set the claims if they have been found if ( claimNamesJsonString != None and claimsSrcJsonString != None ): # Get the claims object jsonWebResponse = dynamicScopeContext.getJsonWebResponse() claims = jsonWebResponse.getClaims() # create JSON objects claimNamesJson = JSONObject(claimNamesJsonString) claimsSrcJson = JSONObject(claimsSrcJsonString) # set the claims claims.setClaim("_claim_names", claimNamesJson) claims.setClaim("_claim_sources", claimsSrcJson) return True