From 7b66f2b27517ba560555f64d0ab4e49f10ddb374 Mon Sep 17 00:00:00 2001 From: Madhumita Subramaniam Date: Tue, 15 Nov 2022 23:51:39 +0530 Subject: [PATCH] fix: #2487 scripts-catalog folder restructuring (#2999) * fix: #2487 scripts-catalog folder restructuring * fix: user-cert-external-authenticator #2487 * fix: #2487 --- .../agama-bridge/AgamaBridge.py | 2 +- .../bioid/BioIDExternalAuthenticator.py | 0 .../person_authentication}/bioid/README.txt | 0 .../forgot_password/README.md | 0 .../forgot_password/forgot_password.py | 0 .../person_authentication/AgamaBridge.py | 180 --- .../BasicExternalAuthenticator.py | 88 -- .../BasicLockAccountExternalAuthenticator.py | 271 ----- .../OtpExternalAuthenticator.py | 615 ---------- .../SuperGluuExternalAuthenticator.py | 1040 ----------------- .../UserCertExternalAuthenticator.py | 485 -------- .../YubicloudExternalAuthenticator.py | 118 -- .../person_authentication/smpp2FA.py | 435 ------- .../person_authentication/twilio2FA.py | 251 ---- .../jans_setup/templates/scripts.ldif | 20 +- 15 files changed, 11 insertions(+), 3494 deletions(-) rename {jans-linux-setup/jans_setup/static/extension/person_authentication/other => docs/script-catalog/person_authentication}/bioid/BioIDExternalAuthenticator.py (100%) rename {jans-linux-setup/jans_setup/static/extension/person_authentication/other => docs/script-catalog/person_authentication}/bioid/README.txt (100%) rename {jans-linux-setup/jans_setup/static/extension/person_authentication/other => docs/script-catalog/person_authentication}/forgot_password/README.md (100%) rename {jans-linux-setup/jans_setup/static/extension/person_authentication/other => docs/script-catalog/person_authentication}/forgot_password/forgot_password.py (100%) delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/AgamaBridge.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/BasicExternalAuthenticator.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/BasicLockAccountExternalAuthenticator.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/OtpExternalAuthenticator.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/SuperGluuExternalAuthenticator.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/UserCertExternalAuthenticator.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/YubicloudExternalAuthenticator.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/smpp2FA.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/twilio2FA.py diff --git a/docs/script-catalog/person_authentication/agama-bridge/AgamaBridge.py b/docs/script-catalog/person_authentication/agama-bridge/AgamaBridge.py index c6af9a80013..3983d25f6bf 100644 --- a/docs/script-catalog/person_authentication/agama-bridge/AgamaBridge.py +++ b/docs/script-catalog/person_authentication/agama-bridge/AgamaBridge.py @@ -177,4 +177,4 @@ def extractParams(self, param): elif i == -1: return (param, None) else: - return (param[:i], param[i:]) + return (param[:i], param[i+1:]) diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/bioid/BioIDExternalAuthenticator.py b/docs/script-catalog/person_authentication/bioid/BioIDExternalAuthenticator.py similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/bioid/BioIDExternalAuthenticator.py rename to docs/script-catalog/person_authentication/bioid/BioIDExternalAuthenticator.py diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/bioid/README.txt b/docs/script-catalog/person_authentication/bioid/README.txt similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/bioid/README.txt rename to docs/script-catalog/person_authentication/bioid/README.txt diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/forgot_password/README.md b/docs/script-catalog/person_authentication/forgot_password/README.md similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/forgot_password/README.md rename to docs/script-catalog/person_authentication/forgot_password/README.md diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/forgot_password/forgot_password.py b/docs/script-catalog/person_authentication/forgot_password/forgot_password.py similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/forgot_password/forgot_password.py rename to docs/script-catalog/person_authentication/forgot_password/forgot_password.py diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/AgamaBridge.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/AgamaBridge.py deleted file mode 100644 index 3983d25f6bf..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/AgamaBridge.py +++ /dev/null @@ -1,180 +0,0 @@ -# Janssen Project software is available under the Apache 2.0 License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -from io.jans.agama import NativeJansFlowBridge -from io.jans.agama.engine.misc import FlowUtils -from io.jans.as.server.security import Identity -from io.jans.as.server.service import AuthenticationService -from io.jans.jsf2.service import FacesService -from io.jans.jsf2.message import FacesMessages -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.orm import PersistenceEntryManager -from io.jans.service.cdi.util import CdiUtil -from io.jans.util import StringHelper - -from jakarta.faces.application import FacesMessage - -import java -import sys - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - print "Agama. Initialization" - prop = "cust_param_name" - self.cust_param_name = self.configProperty(configurationAttributes, prop) - - if self.cust_param_name == None: - print "Agama. Custom parameter name not referenced via property '%s'" % prop - return False - - print "Agama. Request param '%s' will be used to pass flow inputs" % self.cust_param_name - print "Agama. Initialized successfully" - return True - - def destroy(self, configurationAttributes): - print "Agama. Destroy" - print "Agama. Destroyed successfully" - return True - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def getApiVersion(self): - return 11 - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - def authenticate(self, configurationAttributes, requestParameters, step): - - if step == 1: - print "Agama. Authenticate for step 1" - - try: - bridge = CdiUtil.bean(NativeJansFlowBridge) - result = bridge.close() - - if result == None or not result.isSuccess(): - print "Agama. Flow DID NOT finished successfully" - return False - else: - print "Agama. Flow finished successfully" - data = result.getData() - userId = data.get("userId") if data != None else None - - if userId == None: - print "Agama. No userId provided in flow result." - self.setMessageError(FacesMessage.SEVERITY_ERROR, "Unable to determine identity of user") - return False - - authenticated = CdiUtil.bean(AuthenticationService).authenticate(userId) - - if not authenticated: - print "Agama. Unable to authenticate %s" % userId - return False - except: - print "Agama. Exception: ", sys.exc_info()[1] - return False - - return True - - - def prepareForStep(self, configurationAttributes, requestParameters, step): - - if not CdiUtil.bean(FlowUtils).serviceEnabled(): - print "Agama. Please ENABLE Agama engine in auth-server configuration" - return False - - if step == 1: - print "Agama. Prepare for Step 1" - - session = CdiUtil.bean(Identity).getSessionId() - if session == None: - print "Agama. Failed to retrieve session_id" - return False - - param = session.getSessionAttributes().get(self.cust_param_name) - if param == None: - print "Agama. Request param '%s' is missing or has no value" % self.cust_param_name - return False - - (qn, ins) = self.extractParams(param) - if qn == None: - print "Agama. Param '%s' is missing the name of the flow to be launched" % self.cust_param_name - return False - - try: - bridge = CdiUtil.bean(NativeJansFlowBridge) - running = bridge.prepareFlow(session.getId(), qn, ins) - - if running == None: - print "Agama. Flow '%s' does not exist!" % qn - return False - elif running: - print "Agama. A flow is already in course" - - print "Agama. Redirecting to start/resume agama flow '%s'..." % qn - - CdiUtil.bean(FacesService).redirectToExternalURL(bridge.getTriggerUrl()) - except: - print "Agama. An error occurred when launching flow '%s'. Check jans-auth logs" % qn - print "Agama. Exception: ", sys.exc_info()[1] - return False - #except java.lang.Throwable, ex: - # ex.printStackTrace() - # return False - return True - - def getExtraParametersForStep(self, configurationAttributes, step): - return None - - def getCountAuthenticationSteps(self, configurationAttributes): - return 1 - - def getPageForStep(self, configurationAttributes, step): - # page referenced here is only used when a flow is restarted - return "/" + CdiUtil.bean(NativeJansFlowBridge).scriptPageUrl() - - def getNextStep(self, configurationAttributes, requestParameters, step): - return -1 - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - return None - - def logout(self, configurationAttributes, requestParameters): - return True - -# Misc routines - - def configProperty(self, configProperties, name): - prop = configProperties.get(name) - return None if prop == None else prop.getValue2() - - def setMessageError(self, severity, msg): - facesMessages = CdiUtil.bean(FacesMessages) - facesMessages.setKeepMessages() - facesMessages.clear() - facesMessages.add(severity, msg) - - def extractParams(self, param): - - # param must be of the form QN-INPUT where QN is the qualified name of the flow to launch - # INPUT is a JSON object that contains the arguments to use for the flow call. - # The keys of this object should match the already defined flow inputs. Ideally, and - # depending on the actual flow implementation, some keys may not even be required - # QN and INPUTS are separated by a hyphen - # INPUT must be properly URL-encoded when HTTP GET is used - - i = param.find("-") - if i == 0: - return (None, None) - elif i == -1: - return (param, None) - else: - return (param[:i], param[i+1:]) diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/BasicExternalAuthenticator.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/BasicExternalAuthenticator.py deleted file mode 100644 index 77dcf8ac0b7..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/BasicExternalAuthenticator.py +++ /dev/null @@ -1,88 +0,0 @@ -# Janssen Project software is available under the Apache 2.0 License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Yuriy Movchan -# - -from io.jans.service.cdi.util import CdiUtil -from io.jans.as.server.security import Identity -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.as.server.service import AuthenticationService -from io.jans.util import StringHelper - -import java - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - print "Basic. Initialization" - print "Basic. Initialized successfully" - return True - - def destroy(self, configurationAttributes): - print "Basic. Destroy" - print "Basic. Destroyed successfully" - return True - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def getApiVersion(self): - return 11 - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - def authenticate(self, configurationAttributes, requestParameters, step): - 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 prepareForStep(self, configurationAttributes, requestParameters, step): - if (step == 1): - print "Basic. Prepare for Step 1" - return True - else: - return False - - def getExtraParametersForStep(self, configurationAttributes, step): - return None - - def getCountAuthenticationSteps(self, configurationAttributes): - return 1 - - def getPageForStep(self, configurationAttributes, step): - return "" - - def getNextStep(self, configurationAttributes, requestParameters, step): - return -1 - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Get external logout URL call" - return None - - def logout(self, configurationAttributes, requestParameters): - return True diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/BasicLockAccountExternalAuthenticator.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/BasicLockAccountExternalAuthenticator.py deleted file mode 100644 index f7f2b8d5b45..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/BasicLockAccountExternalAuthenticator.py +++ /dev/null @@ -1,271 +0,0 @@ -# Janssen Project software is available under the Apache 2.0 License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Yuriy Movchan -# Author: Gasmyr Mougang -# - -from io.jans.service.cdi.util import CdiUtil -from io.jans.as.server.security import Identity -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.as.server.service import AuthenticationService -from io.jans.as.server.service import UserService -from io.jans.service import CacheService -from io.jans.util import StringHelper -from io.jans.orm.exception import AuthenticationException -from jakarta.faces.application import FacesMessage -from io.jans.jsf2.message import FacesMessages -from java.time import LocalDateTime, Duration -from java.time.format import DateTimeFormatter - -import java -import datetime -import json - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - print "Basic (lock account). Initialization" - - self.invalidLoginCountAttribute = "jansCountInvalidLogin" - 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 destroy(self, configurationAttributes): - print "Basic (lock account). Destroy" - print "Basic (lock account). Destroyed successfully" - return True - - def getApiVersion(self): - return 11 - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - def authenticate(self, configurationAttributes, requestParameters, step): - authenticationService = CdiUtil.bean(AuthenticationService) - - if step == 1: - print "Basic (lock account). Authenticate for step 1" - facesMessages = CdiUtil.bean(FacesMessages) - facesMessages.setKeepMessages() - identity = CdiUtil.bean(Identity) - credentials = identity.getCredentials() - user_name = credentials.getUsername() - user_password = credentials.getPassword() - cacheService = CdiUtil.bean(CacheService) - userService = CdiUtil.bean(UserService) - - - logged_in = False - if (StringHelper.isNotEmptyString(user_name) and StringHelper.isNotEmptyString(user_password)): - try: - logged_in = authenticationService.authenticate(user_name, user_password) - except AuthenticationException: - print "Basic (lock account). Authenticate. Failed to authenticate user '%s'" % user_name - - if logged_in: - self.setUserAttributeValue(user_name, self.invalidLoginCountAttribute, StringHelper.toString(0)) - else: - countInvalidLoginArributeValue = self.getUserAttributeValue(user_name, self.invalidLoginCountAttribute) - userSatus = self.getUserAttributeValue(user_name, "jansStatus") - print "Current user '%s' status is '%s'" % ( user_name, userSatus ) - - countInvalidLogin = StringHelper.toInteger(countInvalidLoginArributeValue, 0) - - if countInvalidLogin < self.maximumInvalidLoginAttemps: - countInvalidLogin = countInvalidLogin + 1 - remainingAttempts = self.maximumInvalidLoginAttemps - countInvalidLogin - - print "Remaining login count attempts '%s' for user '%s'" % ( remainingAttempts, user_name ) - - self.setUserAttributeValue(user_name, self.invalidLoginCountAttribute, StringHelper.toString(countInvalidLogin)) - if remainingAttempts > 0 and userSatus == "active": - facesMessages.add(FacesMessage.SEVERITY_INFO, StringHelper.toString(remainingAttempts)+" more attempt(s) before account is LOCKED!") - - if (countInvalidLogin >= self.maximumInvalidLoginAttemps) and ((userSatus == None) or (userSatus == "active")): - print "Basic (lock account). Locking '%s' for '%s' seconds" % ( user_name, self.lockExpirationTime) - self.lockUser(user_name) - return False - - if (countInvalidLogin >= self.maximumInvalidLoginAttemps) and userSatus == "inactive": - print "Basic (lock account). User '%s' is locked. Checking if we can unlock him" % user_name - - unlock_and_authenticate = False - - object_from_store = cacheService.get(None, "lock_user_" + user_name) - if object_from_store == None: - # Object in cache was expired. We need to unlock user - print "Basic (lock account). User locking details for user '%s' not exists" % user_name - unlock_and_authenticate = True - else: - # Analyze object from cache - user_lock_details = json.loads(object_from_store) - - user_lock_details_locked = user_lock_details['locked'] - user_lock_details_created = user_lock_details['created'] - user_lock_details_created_date = LocalDateTime.parse(user_lock_details_created, DateTimeFormatter.ISO_LOCAL_DATE_TIME) - user_lock_details_created_diff = Duration.between(user_lock_details_created_date, LocalDateTime.now()).getSeconds() - print "Basic (lock account). Get user '%s' locking details. locked: '%s', Created: '%s', Difference in seconds: '%s'" % ( user_name, user_lock_details_locked, user_lock_details_created, user_lock_details_created_diff ) - - if user_lock_details_locked and user_lock_details_created_diff >= self.lockExpirationTime: - print "Basic (lock account). Unlocking user '%s' after lock expiration" % user_name - unlock_and_authenticate = True - - if unlock_and_authenticate: - self.unLockUser(user_name) - self.setUserAttributeValue(user_name, self.invalidLoginCountAttribute, StringHelper.toString(0)) - logged_in = authenticationService.authenticate(user_name, user_password) - if not logged_in: - # Update number of attempts - self.setUserAttributeValue(user_name, self.invalidLoginCountAttribute, StringHelper.toString(1)) - if self.maximumInvalidLoginAttemps == 1: - # Lock user if maximum count login attempts is 1 - self.lockUser(user_name) - return False - - - return logged_in - else: - return False - - def prepareForStep(self, configurationAttributes, requestParameters, step): - if step == 1: - print "Basic (lock account). Prepare for Step 1" - return True - else: - return False - - def getExtraParametersForStep(self, configurationAttributes, step): - return None - - def getCountAuthenticationSteps(self, configurationAttributes): - return 1 - - def getPageForStep(self, configurationAttributes, step): - return "" - - def getNextStep(self, configurationAttributes, requestParameters, step): - return -1 - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Get external logout URL call" - return None - - def logout(self, configurationAttributes, requestParameters): - return True - - def getUserAttributeValue(self, user_name, attribute_name): - if StringHelper.isEmpty(user_name): - return None - - userService = CdiUtil.bean(UserService) - - find_user_by_uid = userService.getUser(user_name, attribute_name) - if find_user_by_uid == None: - return None - - custom_attribute_value = userService.getCustomAttribute(find_user_by_uid, attribute_name) - if custom_attribute_value == None: - return None - - attribute_value = custom_attribute_value.getValue() - - print "Basic (lock account). Get user attribute. User's '%s' attribute '%s' value is '%s'" % (user_name, attribute_name, attribute_value) - - return attribute_value - - def setUserAttributeValue(self, user_name, attribute_name, attribute_value): - if StringHelper.isEmpty(user_name): - return None - - userService = CdiUtil.bean(UserService) - - find_user_by_uid = userService.getUser(user_name) - if find_user_by_uid == None: - return None - - userService.setCustomAttribute(find_user_by_uid, attribute_name, attribute_value) - updated_user = userService.updateUser(find_user_by_uid) - - print "Basic (lock account). Set user attribute. User's '%s' attribute '%s' value is '%s'" % (user_name, attribute_name, attribute_value) - - return updated_user - - 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 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, "jansStatus", "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 diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/OtpExternalAuthenticator.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/OtpExternalAuthenticator.py deleted file mode 100644 index ac11e12fb0a..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/OtpExternalAuthenticator.py +++ /dev/null @@ -1,615 +0,0 @@ -# Janssen Project software is available under the Apache 2.0 License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Yuriy Movchan -# - -# Requires the following custom properties and values: -# otp_type: totp/hotp -# issuer: Janssen Inc -# otp_conf_file: /etc/certs/otp_configuration.json -# -# These are non mandatory custom properties and values: -# label: Janssen OTP -# qr_options: { width: 400, height: 400 } -# registration_uri: https://ce-dev.jans.org/identity/register - -import jarray -import json -import sys -from com.google.common.io import BaseEncoding -from com.lochbridge.oath.otp import HOTP -from com.lochbridge.oath.otp import HOTPValidator -from com.lochbridge.oath.otp import HmacShaAlgorithm -from com.lochbridge.oath.otp import TOTP -from com.lochbridge.oath.otp.keyprovisioning import OTPAuthURIBuilder -from com.lochbridge.oath.otp.keyprovisioning import OTPKey -from com.lochbridge.oath.otp.keyprovisioning.OTPKey import OTPType -from java.security import SecureRandom -from java.util import Arrays -from java.util.concurrent import TimeUnit -from jakarta.faces.application import FacesMessage -from io.jans.jsf2.message import FacesMessages -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.as.server.security import Identity -from io.jans.as.server.service import AuthenticationService -from io.jans.as.server.service import SessionIdService -from io.jans.as.server.service import UserService -from io.jans.as.server.util import ServerUtil -from io.jans.service.cdi.util import CdiUtil -from io.jans.util import StringHelper - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - print "OTP. Initialization" - - if not configurationAttributes.containsKey("otp_type"): - print "OTP. Initialization. Property otp_type is mandatory" - return False - self.otpType = configurationAttributes.get("otp_type").getValue2() - - if not self.otpType in ["hotp", "totp"]: - print "OTP. Initialization. Property value otp_type is invalid" - return False - - if not configurationAttributes.containsKey("issuer"): - print "OTP. Initialization. Property issuer is mandatory" - return False - self.otpIssuer = configurationAttributes.get("issuer").getValue2() - - self.customLabel = None - if configurationAttributes.containsKey("label"): - self.customLabel = configurationAttributes.get("label").getValue2() - - self.customQrOptions = {} - if configurationAttributes.containsKey("qr_options"): - self.customQrOptions = configurationAttributes.get("qr_options").getValue2() - - self.registrationUri = None - if configurationAttributes.containsKey("registration_uri"): - self.registrationUri = configurationAttributes.get("registration_uri").getValue2() - - validOtpConfiguration = self.loadOtpConfiguration(configurationAttributes) - if not validOtpConfiguration: - return False - - print "OTP. Initialized successfully" - return True - - def destroy(self, configurationAttributes): - print "OTP. Destroy" - print "OTP. Destroyed successfully" - return True - - def getApiVersion(self): - return 11 - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def getNextStep(self, configurationAttributes, requestParameters, step): - print "getNextStep Invoked" - # If user not pass current step change step to previous - identity = CdiUtil.bean(Identity) - retry_current_step = identity.getWorkingParameter("retry_current_step") - if retry_current_step: - print "OTP. Get next step. Retrying current step %s" % step - # Remove old QR code - #identity.setWorkingParameter("super_gluu_request", "timeout") - resultStep = step - return resultStep - return -1 - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - 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" - 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" - - 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 - identity.setWorkingParameter("retry_current_step", False) - 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): - # defect fix #1225 - Retry the step, show QR code again - if auth_result == 'timeout': - print "OTP. QR-code timeout. Authenticate for step %s. Reinitializing current step" % step - identity.setWorkingParameter("retry_current_step", True) - return True - - 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 prepareForStep(self, configurationAttributes, requestParameters, step): - identity = CdiUtil.bean(Identity) - credentials = identity.getCredentials() - - self.setRequestScopedParameters(identity) - - if step == 1: - print "OTP. Prepare for step 1" - - return True - elif step == 2: - print "OTP. Prepare for step 2" - - session_id_validation = self.validateSessionId(identity) - if not session_id_validation: - return False - - otp_auth_method = identity.getWorkingParameter("otp_auth_method") - print "OTP. Prepare for step 2. otp_auth_method: '%s'" % otp_auth_method - - if otp_auth_method == 'enroll': - authenticationService = CdiUtil.bean(AuthenticationService) - user = authenticationService.getAuthenticatedUser() - if user == None: - print "OTP. Prepare for step 2. Failed to load user enty" - return False - - if self.otpType == "hotp": - otp_secret_key = self.generateSecretHotpKey() - otp_enrollment_request = self.generateHotpSecretKeyUri(otp_secret_key, self.otpIssuer, user.getAttribute("displayName")) - elif self.otpType == "totp": - otp_secret_key = self.generateSecretTotpKey() - otp_enrollment_request = self.generateTotpSecretKeyUri(otp_secret_key, self.otpIssuer, user.getAttribute("displayName")) - else: - print "OTP. Prepare for step 2. Unknown OTP type: '%s'" % self.otpType - return False - - print "OTP. Prepare for step 2. Prepared enrollment request for user: '%s'" % user.getUserId() - identity.setWorkingParameter("otp_secret_key", self.toBase64Url(otp_secret_key)) - identity.setWorkingParameter("otp_enrollment_request", otp_enrollment_request) - - return True - elif step == 3: - print "OTP. Prepare for step 3" - - session_id_validation = self.validateSessionId(identity) - if not session_id_validation: - return False - - otp_auth_method = identity.getWorkingParameter("otp_auth_method") - print "OTP. Prepare for step 3. otp_auth_method: '%s'" % otp_auth_method - - if otp_auth_method == 'enroll': - return True - - return False - - def getExtraParametersForStep(self, configurationAttributes, step): - return Arrays.asList("otp_auth_method", "otp_count_login_steps", "otp_secret_key", "otp_enrollment_request","retry_current_step") - - 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 getPageForStep(self, configurationAttributes, step): - if step == 2: - identity = CdiUtil.bean(Identity) - - otp_auth_method = identity.getWorkingParameter("otp_auth_method") - print "OTP. Gep page for step 2. otp_auth_method: '%s'" % otp_auth_method - - if otp_auth_method == 'enroll': - return "/auth/otp/enroll.xhtml" - else: - return "/auth/otp/otplogin.xhtml" - elif step == 3: - return "/auth/otp/otplogin.xhtml" - - return "" - - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Get external logout URL call" - return None - - def logout(self, configurationAttributes, requestParameters): - return True - - def setRequestScopedParameters(self, identity): - if self.registrationUri != None: - identity.setWorkingParameter("external_registration_uri", self.registrationUri) - - if self.customLabel != None: - identity.setWorkingParameter("qr_label", self.customLabel) - - identity.setWorkingParameter("qr_options", self.customQrOptions) - - 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 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 "OTP. Process basic authentication. Failed to find user '%s'" % user_name - return None - - return find_user_by_uid - - def findEnrollments(self, user_name, skipPrefix = True): - result = [] - - userService = CdiUtil.bean(UserService) - user = userService.getUser(user_name, "jansExtUid") - if user == None: - print "OTP. Find enrollments. Failed to find user" - return result - - user_custom_ext_attribute = userService.getCustomAttribute(user, "jansExtUid") - if user_custom_ext_attribute == None: - return result - - otp_prefix = "%s:" % self.otpType - - otp_prefix_length = len(otp_prefix) - for user_external_uid in user_custom_ext_attribute.getValues(): - index = user_external_uid.find(otp_prefix) - if index != -1: - if skipPrefix: - enrollment_uid = user_external_uid[otp_prefix_length:] - else: - enrollment_uid = user_external_uid - - result.append(enrollment_uid) - - return result - - def validateSessionId(self, identity): - session = CdiUtil.bean(SessionIdService).getSessionId() - if session == None: - 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 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, "jansExtUid", otp_user_external_uid, True) - 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,user_name) - 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, "jansExtUid", otp_user_external_uid, True) - 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": - user_enrollments = self.findEnrollments(user_name) - - 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 self.otpType == "hotp": - 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, "jansExtUid", otp_user_external_uid, new_otp_user_external_uid, True) - if find_user_by_external_uid != None: - return True - - print "OTP. Process HOTP authentication during authentication. Failed to update user entry" - elif self.otpType == "totp": - for user_enrollment in user_enrollments: - otp_secret_key = self.fromBase64Url(user_enrollment) - - # Validate TOTP - validation_result = self.validateTotpKey(otp_secret_key, otpCode, user_name) - 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 - - # Shared HOTP/TOTP methods - def generateSecretKey(self, keyLength): - bytes = jarray.zeros(keyLength, "b") - secureRandom = SecureRandom() - secureRandom.nextBytes(bytes) - - return bytes - - # HOTP methods - def generateSecretHotpKey(self): - keyLength = self.hotpConfiguration["keyLength"] - - return self.generateSecretKey(keyLength) - - def generateHotpKey(self, secretKey, movingFactor): - digits = self.hotpConfiguration["digits"] - - hotp = HOTP.key(secretKey).digits(digits).movingFactor(movingFactor).build() - - return hotp.value() - - def validateHotpKey(self, secretKey, movingFactor, totpKey): - lookAheadWindow = self.hotpConfiguration["lookAheadWindow"] - digits = self.hotpConfiguration["digits"] - - htopValidationResult = HOTPValidator.lookAheadWindow(lookAheadWindow).validate(secretKey, movingFactor, digits, totpKey) - if htopValidationResult.isValid(): - return { "result": True, "movingFactor": htopValidationResult.getNewMovingFactor() } - - return { "result": False, "movingFactor": None } - - def generateHotpSecretKeyUri(self, secretKey, issuer, userDisplayName): - digits = self.hotpConfiguration["digits"] - - secretKeyBase32 = self.toBase32(secretKey) - otpKey = OTPKey(secretKeyBase32, OTPType.HOTP) - label = issuer + " %s" % userDisplayName - - otpAuthURI = OTPAuthURIBuilder.fromKey(otpKey).label(label).issuer(issuer).digits(digits).build() - - return otpAuthURI.toUriString() - - # TOTP methods - def generateSecretTotpKey(self): - keyLength = self.totpConfiguration["keyLength"] - - return self.generateSecretKey(keyLength) - - def generateTotpKey(self, secretKey): - digits = self.totpConfiguration["digits"] - timeStep = self.totpConfiguration["timeStep"] - hmacShaAlgorithmType = self.totpConfiguration["hmacShaAlgorithmType"] - - totp = TOTP.key(secretKey).digits(digits).timeStep(TimeUnit.SECONDS.toMillis(timeStep)).hmacSha(hmacShaAlgorithmType).build() - - return totp.value() - - def validateTotpKey(self, secretKey, totpKey, user_name): - localTotpKey = self.generateTotpKey(secretKey) - cachedOTP = self.getCachedOTP(user_name) - - if StringHelper.equals(localTotpKey, totpKey) and not StringHelper.equals(localTotpKey, cachedOTP): - userService = CdiUtil.bean(UserService) - if cachedOTP is None: - userService.addUserAttribute(user_name, "jansOTPCache",localTotpKey) - else : - userService.replaceUserAttribute(user_name, "jansOTPCache", cachedOTP, localTotpKey) - print "OTP. Caching OTP: '%s'" % localTotpKey - return { "result": True } - return { "result": False } - - def getCachedOTP(self, user_name): - userService = CdiUtil.bean(UserService) - user = userService.getUser(user_name, "jansOTPCache") - if user is None: - print "OTP. Get Cached OTP. Failed to find OTP" - return None - customAttribute = userService.getCustomAttribute(user, "jansOTPCache") - - if customAttribute is None: - print "OTP. Custom attribute is null" - return None - user_cached_OTP = customAttribute.getValue() - if user_cached_OTP is None: - print "OTP. no OTP is present in LDAP" - return None - - print "OTP.Cached OTP: '%s'" % user_cached_OTP - return user_cached_OTP - - def generateTotpSecretKeyUri(self, secretKey, issuer, userDisplayName): - digits = self.totpConfiguration["digits"] - timeStep = self.totpConfiguration["timeStep"] - - secretKeyBase32 = self.toBase32(secretKey) - otpKey = OTPKey(secretKeyBase32, OTPType.TOTP) - label = issuer + " %s" % userDisplayName - - otpAuthURI = OTPAuthURIBuilder.fromKey(otpKey).label(label).issuer(issuer).digits(digits).timeStep(TimeUnit.SECONDS.toMillis(timeStep)).build() - - return otpAuthURI.toUriString() - - # Utility methods - def toBase32(self, bytes): - return BaseEncoding.base32().omitPadding().encode(bytes) - - def toBase64Url(self, bytes): - return BaseEncoding.base64Url().encode(bytes) - - def fromBase64Url(self, chars): - return BaseEncoding.base64Url().decode(chars) diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/SuperGluuExternalAuthenticator.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/SuperGluuExternalAuthenticator.py deleted file mode 100644 index 83098109875..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/SuperGluuExternalAuthenticator.py +++ /dev/null @@ -1,1040 +0,0 @@ -# Janssen Project software is available under the Apache 2.0 License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Yuriy Movchan -# - -from com.google.android.gcm.server import Sender, Message -from com.notnoop.apns import APNS -from java.util import Arrays -from org.apache.http.params import CoreConnectionPNames -from io.jans.service.cdi.util import CdiUtil -from io.jans.as.server.security import Identity -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.as.server.model.config import ConfigurationFactory -from io.jans.as.server.service import AuthenticationService -from io.jans.as.server.service import SessionIdService -from io.jans.as.server.service.fido.u2f import DeviceRegistrationService -from io.jans.as.server.service.net import HttpService -from io.jans.as.server.util import ServerUtil -from io.jans.util import StringHelper -from io.jans.as.common.service.common import EncryptionService -from io.jans.as.server.service import UserService -from io.jans.service import MailService -from io.jans.as.server.service.push.sns import PushPlatform -from io.jans.as.server.service.push.sns import PushSnsService -from io.jans.notify.client import NotifyClientFactory -from java.util import Arrays, HashMap, IdentityHashMap, Date -from java.time import ZonedDateTime -from java.time.format import DateTimeFormatter - -import datetime -import urllib - -import sys -import json - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - print "Super-Gluu. Initialization" - - if not configurationAttributes.containsKey("authentication_mode"): - print "Super-Gluu. Initialization. Property authentication_mode is mandatory" - return False - - self.applicationId = None - if configurationAttributes.containsKey("application_id"): - self.applicationId = configurationAttributes.get("application_id").getValue2() - - self.registrationUri = None - if configurationAttributes.containsKey("registration_uri"): - self.registrationUri = configurationAttributes.get("registration_uri").getValue2() - - authentication_mode = configurationAttributes.get("authentication_mode").getValue2() - if StringHelper.isEmpty(authentication_mode): - print "Super-Gluu. Initialization. Failed to determine authentication_mode. authentication_mode configuration parameter is empty" - return False - - self.oneStep = StringHelper.equalsIgnoreCase(authentication_mode, "one_step") - self.twoStep = StringHelper.equalsIgnoreCase(authentication_mode, "two_step") - - if not (self.oneStep or self.twoStep): - print "Super-Gluu. Initialization. Valid authentication_mode values are one_step and two_step" - return False - - self.enabledPushNotifications = self.initPushNotificationService(configurationAttributes) - - self.androidUrl = None - if configurationAttributes.containsKey("supergluu_android_download_url"): - self.androidUrl = configurationAttributes.get("supergluu_android_download_url").getValue2() - - self.IOSUrl = None - if configurationAttributes.containsKey("supergluu_ios_download_url"): - self.IOSUrl = configurationAttributes.get("supergluu_ios_download_url").getValue2() - - self.customLabel = None - if configurationAttributes.containsKey("label"): - self.customLabel = configurationAttributes.get("label").getValue2() - - self.customQrOptions = {} - if configurationAttributes.containsKey("qr_options"): - self.customQrOptions = configurationAttributes.get("qr_options").getValue2() - - self.use_super_gluu_group = False - if configurationAttributes.containsKey("super_gluu_group"): - self.super_gluu_group = configurationAttributes.get("super_gluu_group").getValue2() - self.use_super_gluu_group = True - print "Super-Gluu. Initialization. Using super_gluu only if user belong to group: %s" % self.super_gluu_group - - self.use_audit_group = False - if configurationAttributes.containsKey("audit_group"): - self.audit_group = configurationAttributes.get("audit_group").getValue2() - - if (not configurationAttributes.containsKey("audit_group_email")): - print "Super-Gluu. Initialization. Property audit_group_email is not specified" - return False - - self.audit_email = configurationAttributes.get("audit_group_email").getValue2() - self.use_audit_group = True - - print "Super-Gluu. Initialization. Using audit group: %s" % self.audit_group - - if self.use_super_gluu_group or self.use_audit_group: - if not configurationAttributes.containsKey("audit_attribute"): - print "Super-Gluu. Initialization. Property audit_attribute is not specified" - return False - else: - self.audit_attribute = configurationAttributes.get("audit_attribute").getValue2() - - print "Super-Gluu. Initialized successfully. oneStep: '%s', twoStep: '%s', pushNotifications: '%s', customLabel: '%s'" % (self.oneStep, self.twoStep, self.enabledPushNotifications, self.customLabel) - - return True - - def destroy(self, configurationAttributes): - print "Super-Gluu. Destroy" - - self.pushAndroidService = None - self.pushAppleService = None - - print "Super-Gluu. Destroyed successfully" - return True - - def getApiVersion(self): - return 11 - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - def authenticate(self, configurationAttributes, requestParameters, step): - authenticationService = CdiUtil.bean(AuthenticationService) - - identity = CdiUtil.bean(Identity) - credentials = identity.getCredentials() - - session_attributes = identity.getSessionId().getSessionAttributes() - - client_redirect_uri = self.getApplicationUri(session_attributes) - if client_redirect_uri == None: - print "Super-Gluu. Authenticate. redirect_uri is not set" - return False - - self.setRequestScopedParameters(identity, step) - - # Validate form result code and initialize QR code regeneration if needed (retry_current_step = True) - identity.setWorkingParameter("retry_current_step", False) - form_auth_result = ServerUtil.getFirstValue(requestParameters, "auth_result") - if StringHelper.isNotEmpty(form_auth_result): - print "Super-Gluu. Authenticate for step %s. Get auth_result: '%s'" % (step, form_auth_result) - if form_auth_result in ['error']: - return False - - if form_auth_result in ['timeout']: - if ((step == 1) and self.oneStep) or ((step == 2) and self.twoStep): - print "Super-Gluu. Authenticate for step %s. Reinitializing current step" % step - identity.setWorkingParameter("retry_current_step", True) - return False - - userService = CdiUtil.bean(UserService) - deviceRegistrationService = CdiUtil.bean(DeviceRegistrationService) - if step == 1: - print "Super-Gluu. Authenticate for step 1" - - user_name = credentials.getUsername() - if self.oneStep: - session_device_status = self.getSessionDeviceStatus(session_attributes, user_name) - if session_device_status == None: - return False - - u2f_device_id = session_device_status['device_id'] - - validation_result = self.validateSessionDeviceStatus(client_redirect_uri, session_device_status) - if validation_result: - print "Super-Gluu. Authenticate for step 1. User successfully authenticated with u2f_device '%s'" % u2f_device_id - else: - return False - - if not session_device_status['one_step']: - print "Super-Gluu. Authenticate for step 1. u2f_device '%s' is not one step device" % u2f_device_id - return False - - # There are two steps only in enrollment mode - if session_device_status['enroll']: - return validation_result - - identity.setWorkingParameter("super_gluu_count_login_steps", 1) - - user_inum = session_device_status['user_inum'] - - u2f_device = deviceRegistrationService.findUserDeviceRegistration(user_inum, u2f_device_id, "jansId") - if u2f_device == None: - print "Super-Gluu. Authenticate for step 1. Failed to load u2f_device '%s'" % u2f_device_id - return False - - logged_in = authenticationService.authenticate(user_name) - if not logged_in: - print "Super-Gluu. Authenticate for step 1. Failed to authenticate user '%s'" % user_name - return False - - print "Super-Gluu. Authenticate for step 1. User '%s' successfully authenticated with u2f_device '%s'" % (user_name, u2f_device_id) - - return True - elif self.twoStep: - authenticated_user = self.processBasicAuthentication(credentials) - if authenticated_user == None: - return False - - if (self.use_super_gluu_group): - print "Super-Gluu. Authenticate for step 1. Checking if user belong to super_gluu group" - is_member_super_gluu_group = self.isUserMemberOfGroup(authenticated_user, self.audit_attribute, self.super_gluu_group) - if (is_member_super_gluu_group): - print "Super-Gluu. Authenticate for step 1. User '%s' member of super_gluu group" % authenticated_user.getUserId() - super_gluu_count_login_steps = 2 - else: - if self.use_audit_group: - self.processAuditGroup(authenticated_user, self.audit_attribute, self.audit_group) - super_gluu_count_login_steps = 1 - - identity.setWorkingParameter("super_gluu_count_login_steps", super_gluu_count_login_steps) - - if super_gluu_count_login_steps == 1: - return True - - auth_method = 'authenticate' - enrollment_mode = ServerUtil.getFirstValue(requestParameters, "loginForm:registerButton") - if StringHelper.isNotEmpty(enrollment_mode): - auth_method = 'enroll' - - if auth_method == 'authenticate': - user_inum = userService.getUserInum(authenticated_user) - u2f_devices_list = deviceRegistrationService.findUserDeviceRegistrations(user_inum, client_redirect_uri, "jansId") - if u2f_devices_list.size() == 0: - auth_method = 'enroll' - print "Super-Gluu. Authenticate for step 1. There is no U2F '%s' user devices associated with application '%s'. Changing auth_method to '%s'" % (user_name, client_redirect_uri, auth_method) - - print "Super-Gluu. Authenticate for step 1. auth_method: '%s'" % auth_method - - identity.setWorkingParameter("super_gluu_auth_method", auth_method) - - return True - - return False - elif step == 2: - print "Super-Gluu. Authenticate for step 2" - - user = authenticationService.getAuthenticatedUser() - if (user == None): - print "Super-Gluu. Authenticate for step 2. Failed to determine user name" - return False - user_name = user.getUserId() - - session_attributes = identity.getSessionId().getSessionAttributes() - - session_device_status = self.getSessionDeviceStatus(session_attributes, user_name) - if session_device_status == None: - return False - - u2f_device_id = session_device_status['device_id'] - - # There are two steps only in enrollment mode - if self.oneStep and session_device_status['enroll']: - authenticated_user = self.processBasicAuthentication(credentials) - if authenticated_user == None: - return False - - user_inum = userService.getUserInum(authenticated_user) - - attach_result = deviceRegistrationService.attachUserDeviceRegistration(user_inum, u2f_device_id) - - print "Super-Gluu. Authenticate for step 2. Result after attaching u2f_device '%s' to user '%s': '%s'" % (u2f_device_id, user_name, attach_result) - - return attach_result - elif self.twoStep: - if user_name == None: - print "Super-Gluu. Authenticate for step 2. Failed to determine user name" - return False - - validation_result = self.validateSessionDeviceStatus(client_redirect_uri, session_device_status, user_name) - if validation_result: - print "Super-Gluu. Authenticate for step 2. User '%s' successfully authenticated with u2f_device '%s'" % (user_name, u2f_device_id) - else: - return False - - super_gluu_request = json.loads(session_device_status['super_gluu_request']) - auth_method = super_gluu_request['method'] - if auth_method in ['enroll', 'authenticate']: - if validation_result and self.use_audit_group: - user = authenticationService.getAuthenticatedUser() - self.processAuditGroup(user, self.audit_attribute, self.audit_group) - - return validation_result - - print "Super-Gluu. Authenticate for step 2. U2F auth_method is invalid" - - return False - else: - return False - - def prepareForStep(self, configurationAttributes, requestParameters, step): - identity = CdiUtil.bean(Identity) - session_attributes = identity.getSessionId().getSessionAttributes() - - client_redirect_uri = self.getApplicationUri(session_attributes) - if client_redirect_uri == None: - print "Super-Gluu. Prepare for step. redirect_uri is not set" - return False - - self.setRequestScopedParameters(identity, step) - - if step == 1: - print "Super-Gluu. Prepare for step 1" - if self.oneStep: - session = CdiUtil.bean(SessionIdService).getSessionId() - if session == None: - print "Super-Gluu. Prepare for step 2. Failed to determine session_id" - return False - - issuer = CdiUtil.bean(ConfigurationFactory).getConfiguration().getIssuer() - super_gluu_request_dictionary = {'app': client_redirect_uri, - 'issuer': issuer, - 'state': session.getId(), - 'created': DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(ZonedDateTime.now().withNano(0))} - - self.addGeolocationData(session_attributes, super_gluu_request_dictionary) - - super_gluu_request = json.dumps(super_gluu_request_dictionary, separators=(',',':')) - print "Super-Gluu. Prepare for step 1. Prepared super_gluu_request:", super_gluu_request - - identity.setWorkingParameter("super_gluu_request", super_gluu_request) - elif self.twoStep: - identity.setWorkingParameter("display_register_action", True) - - return True - elif step == 2: - print "Super-Gluu. Prepare for step 2" - if self.oneStep: - return True - - authenticationService = CdiUtil.bean(AuthenticationService) - user = authenticationService.getAuthenticatedUser() - if user == None: - print "Super-Gluu. Prepare for step 2. Failed to determine user name" - return False - - if session_attributes.containsKey("super_gluu_request"): - super_gluu_request = session_attributes.get("super_gluu_request") - if not StringHelper.equalsIgnoreCase(super_gluu_request, "timeout"): - print "Super-Gluu. Prepare for step 2. Request was generated already" - return True - - session = CdiUtil.bean(SessionIdService).getSessionId() - if session == None: - print "Super-Gluu. Prepare for step 2. Failed to determine session_id" - return False - - auth_method = session_attributes.get("super_gluu_auth_method") - if StringHelper.isEmpty(auth_method): - print "Super-Gluu. Prepare for step 2. Failed to determine auth_method" - return False - - print "Super-Gluu. Prepare for step 2. auth_method: '%s'" % auth_method - - issuer = CdiUtil.bean(ConfigurationFactory).getAppConfiguration().getIssuer() - super_gluu_request_dictionary = {'username': user.getUserId(), - 'app': client_redirect_uri, - 'issuer': issuer, - 'method': auth_method, - 'state': session.getId(), - 'created': DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(ZonedDateTime.now().withNano(0))} - - self.addGeolocationData(session_attributes, super_gluu_request_dictionary) - - super_gluu_request = json.dumps(super_gluu_request_dictionary, separators=(',',':')) - print "Super-Gluu. Prepare for step 2. Prepared super_gluu_request:", super_gluu_request - - identity.setWorkingParameter("super_gluu_request", super_gluu_request) - identity.setWorkingParameter("super_gluu_auth_method", auth_method) - - if auth_method in ['authenticate']: - self.sendPushNotification(client_redirect_uri, user, super_gluu_request) - - return True - else: - return False - - def getNextStep(self, configurationAttributes, requestParameters, step): - # If user not pass current step change step to previous - identity = CdiUtil.bean(Identity) - retry_current_step = identity.getWorkingParameter("retry_current_step") - if retry_current_step: - print "Super-Gluu. Get next step. Retrying current step" - - # Remove old QR code - identity.setWorkingParameter("super_gluu_request", "timeout") - - resultStep = step - return resultStep - - return -1 - - def getExtraParametersForStep(self, configurationAttributes, step): - if step == 1: - if self.oneStep: - return Arrays.asList("super_gluu_request") - elif self.twoStep: - return Arrays.asList("display_register_action") - elif step == 2: - return Arrays.asList("super_gluu_auth_method", "super_gluu_request") - - return None - - def getCountAuthenticationSteps(self, configurationAttributes): - identity = CdiUtil.bean(Identity) - if identity.isSetWorkingParameter("super_gluu_count_login_steps"): - return identity.getWorkingParameter("super_gluu_count_login_steps") - else: - return 2 - - def getPageForStep(self, configurationAttributes, step): - if step == 1: - if self.oneStep: - return "/auth/super-gluu/login.xhtml" - elif step == 2: - if self.oneStep: - return "/login.xhtml" - else: - identity = CdiUtil.bean(Identity) - authmethod = identity.getWorkingParameter("super_gluu_auth_method") - print "Super-Gluu. authmethod '%s'" % authmethod - if authmethod == "enroll": - return "/auth/super-gluu/login.xhtml" - else: - return "/auth/super-gluu/login.xhtml" - - return "" - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Get external logout URL call" - return None - - def logout(self, configurationAttributes, requestParameters): - return True - - def processBasicAuthentication(self, credentials): - 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 "Super-Gluu. Process basic authentication. Failed to find user '%s'" % user_name - return None - - return find_user_by_uid - - def validateSessionDeviceStatus(self, client_redirect_uri, session_device_status, user_name = None): - userService = CdiUtil.bean(UserService) - deviceRegistrationService = CdiUtil.bean(DeviceRegistrationService) - - u2f_device_id = session_device_status['device_id'] - - u2f_device = None - if session_device_status['enroll'] and session_device_status['one_step']: - u2f_device = deviceRegistrationService.findOneStepUserDeviceRegistration(u2f_device_id) - if u2f_device == None: - print "Super-Gluu. Validate session device status. There is no one step u2f_device '%s'" % u2f_device_id - return False - else: - # Validate if user has specified device_id enrollment - user_inum = userService.getUserInum(user_name) - - if session_device_status['one_step']: - user_inum = session_device_status['user_inum'] - - u2f_device = deviceRegistrationService.findUserDeviceRegistration(user_inum, u2f_device_id) - if u2f_device == None: - print "Super-Gluu. Validate session device status. There is no u2f_device '%s' associated with user '%s'" % (u2f_device_id, user_inum) - return False - - if not StringHelper.equalsIgnoreCase(client_redirect_uri, u2f_device.application): - print "Super-Gluu. Validate session device status. u2f_device '%s' associated with other application '%s'" % (u2f_device_id, u2f_device.application) - return False - - return True - - def getSessionDeviceStatus(self, session_attributes, user_name): - print "Super-Gluu. Get session device status" - - if not session_attributes.containsKey("super_gluu_request"): - print "Super-Gluu. Get session device status. There is no Super-Gluu request in session attributes" - return None - - # Check session state extended - if not session_attributes.containsKey("session_custom_state"): - print "Super-Gluu. Get session device status. There is no session_custom_state in session attributes" - return None - - session_custom_state = session_attributes.get("session_custom_state") - if not StringHelper.equalsIgnoreCase("approved", session_custom_state): - print "Super-Gluu. Get session device status. User '%s' not approve or not pass U2F authentication. session_custom_state: '%s'" % (user_name, session_custom_state) - return None - - # Try to find device_id in session attribute - if not session_attributes.containsKey("oxpush2_u2f_device_id"): - print "Super-Gluu. Get session device status. There is no u2f_device associated with this request" - return None - - # Try to find user_inum in session attribute - if not session_attributes.containsKey("oxpush2_u2f_device_user_inum"): - print "Super-Gluu. Get session device status. There is no user_inum associated with this request" - return None - - enroll = False - if session_attributes.containsKey("oxpush2_u2f_device_enroll"): - enroll = StringHelper.equalsIgnoreCase("true", session_attributes.get("oxpush2_u2f_device_enroll")) - - one_step = False - if session_attributes.containsKey("oxpush2_u2f_device_one_step"): - one_step = StringHelper.equalsIgnoreCase("true", session_attributes.get("oxpush2_u2f_device_one_step")) - - super_gluu_request = session_attributes.get("super_gluu_request") - u2f_device_id = session_attributes.get("oxpush2_u2f_device_id") - user_inum = session_attributes.get("oxpush2_u2f_device_user_inum") - - session_device_status = {"super_gluu_request": super_gluu_request, "device_id": u2f_device_id, "user_inum" : user_inum, "enroll" : enroll, "one_step" : one_step} - print "Super-Gluu. Get session device status. session_device_status: '%s'" % (session_device_status) - - return session_device_status - - def initPushNotificationService(self, configurationAttributes): - print "Super-Gluu. Initialize Native/SNS/Gluu notification services" - - self.pushSnsMode = False - self.pushGluuMode = False - if configurationAttributes.containsKey("notification_service_mode"): - notificationServiceMode = configurationAttributes.get("notification_service_mode").getValue2() - if StringHelper.equalsIgnoreCase(notificationServiceMode, "sns"): - return self.initSnsPushNotificationService(configurationAttributes) - elif StringHelper.equalsIgnoreCase(notificationServiceMode, "gluu"): - return self.initGluuPushNotificationService(configurationAttributes) - - return self.initNativePushNotificationService(configurationAttributes) - - def initNativePushNotificationService(self, configurationAttributes): - print "Super-Gluu. Initialize native notification services" - - creds = self.loadPushNotificationCreds(configurationAttributes) - if creds == None: - return False - - try: - android_creds = creds["android"]["gcm"] - ios_creds = creds["ios"]["apns"] - except: - print "Super-Gluu. Initialize native notification services. Invalid credentials file format" - return False - - self.pushAndroidService = None - self.pushAppleService = None - if android_creds["enabled"]: - self.pushAndroidService = Sender(android_creds["api_key"]) - print "Super-Gluu. Initialize native notification services. Created Android notification service" - - if ios_creds["enabled"]: - p12_file_path = ios_creds["p12_file_path"] - p12_password = ios_creds["p12_password"] - - try: - encryptionService = CdiUtil.bean(EncryptionService) - p12_password = encryptionService.decrypt(p12_password) - except: - # Ignore exception. Password is not encrypted - print "Super-Gluu. Initialize native notification services. Assuming that 'p12_password' password in not encrypted" - - apnsServiceBuilder = APNS.newService().withCert(p12_file_path, p12_password) - if ios_creds["production"]: - self.pushAppleService = apnsServiceBuilder.withProductionDestination().build() - else: - self.pushAppleService = apnsServiceBuilder.withSandboxDestination().build() - - self.pushAppleServiceProduction = ios_creds["production"] - - print "Super-Gluu. Initialize native notification services. Created iOS notification service" - - enabled = self.pushAndroidService != None or self.pushAppleService != None - - return enabled - - def initSnsPushNotificationService(self, configurationAttributes): - print "Super-Gluu. Initialize SNS notification services" - self.pushSnsMode = True - - creds = self.loadPushNotificationCreds(configurationAttributes) - if creds == None: - return False - - try: - sns_creds = creds["sns"] - android_creds = creds["android"]["sns"] - ios_creds = creds["ios"]["sns"] - except: - print "Super-Gluu. Initialize SNS notification services. Invalid credentials file format" - return False - - self.pushAndroidService = None - self.pushAppleService = None - if not (android_creds["enabled"] or ios_creds["enabled"]): - print "Super-Gluu. Initialize SNS notification services. SNS disabled for all platforms" - return False - - sns_access_key = sns_creds["access_key"] - sns_secret_access_key = sns_creds["secret_access_key"] - sns_region = sns_creds["region"] - - encryptionService = CdiUtil.bean(EncryptionService) - - try: - sns_secret_access_key = encryptionService.decrypt(sns_secret_access_key) - except: - # Ignore exception. Password is not encrypted - print "Super-Gluu. Initialize SNS notification services. Assuming that 'sns_secret_access_key' in not encrypted" - - pushSnsService = CdiUtil.bean(PushSnsService) - pushClient = pushSnsService.createSnsClient(sns_access_key, sns_secret_access_key, sns_region) - - if android_creds["enabled"]: - self.pushAndroidService = pushClient - self.pushAndroidPlatformArn = android_creds["platform_arn"] - print "Super-Gluu. Initialize SNS notification services. Created Android notification service" - - if ios_creds["enabled"]: - self.pushAppleService = pushClient - self.pushApplePlatformArn = ios_creds["platform_arn"] - self.pushAppleServiceProduction = ios_creds["production"] - print "Super-Gluu. Initialize SNS notification services. Created iOS notification service" - - enabled = self.pushAndroidService != None or self.pushAppleService != None - - return enabled - - def initGluuPushNotificationService(self, configurationAttributes): - print "Super-Gluu. Initialize Gluu notification services" - - self.pushGluuMode = True - - creds = self.loadPushNotificationCreds(configurationAttributes) - if creds == None: - return False - - try: - gluu_conf = creds["gluu"] - android_creds = creds["android"]["gluu"] - ios_creds = creds["ios"]["gluu"] - except: - print "Super-Gluu. Initialize Gluu notification services. Invalid credentials file format" - return False - - self.pushAndroidService = None - self.pushAppleService = None - if not (android_creds["enabled"] or ios_creds["enabled"]): - print "Super-Gluu. Initialize Gluu notification services. Gluu disabled for all platforms" - return False - - gluu_server_uri = gluu_conf["server_uri"] - notifyClientFactory = NotifyClientFactory.instance() - metadataConfiguration = None - try: - metadataConfiguration = notifyClientFactory.createMetaDataConfigurationService(gluu_server_uri).getMetadataConfiguration() - except: - print "Super-Gluu. Initialize Gluu notification services. Failed to load metadata. Exception: ", sys.exc_info()[1] - return False - - gluuClient = notifyClientFactory.createNotifyService(metadataConfiguration) - encryptionService = CdiUtil.bean(EncryptionService) - - if android_creds["enabled"]: - gluu_access_key = android_creds["access_key"] - gluu_secret_access_key = android_creds["secret_access_key"] - - try: - gluu_secret_access_key = encryptionService.decrypt(gluu_secret_access_key) - except: - # Ignore exception. Password is not encrypted - print "Super-Gluu. Initialize Gluu notification services. Assuming that 'gluu_secret_access_key' in not encrypted" - - self.pushAndroidService = gluuClient - self.pushAndroidServiceAuth = notifyClientFactory.getAuthorization(gluu_access_key, gluu_secret_access_key); - print "Super-Gluu. Initialize Gluu notification services. Created Android notification service" - - if ios_creds["enabled"]: - gluu_access_key = ios_creds["access_key"] - gluu_secret_access_key = ios_creds["secret_access_key"] - - try: - gluu_secret_access_key = encryptionService.decrypt(gluu_secret_access_key) - except: - # Ignore exception. Password is not encrypted - print "Super-Gluu. Initialize Gluu notification services. Assuming that 'gluu_secret_access_key' in not encrypted" - - self.pushAppleService = gluuClient - self.pushAppleServiceAuth = notifyClientFactory.getAuthorization(gluu_access_key, gluu_secret_access_key); - print "Super-Gluu. Initialize Gluu notification services. Created iOS notification service" - - enabled = self.pushAndroidService != None or self.pushAppleService != None - - return enabled - - def loadPushNotificationCreds(self, configurationAttributes): - print "Super-Gluu. Initialize notification services" - if not configurationAttributes.containsKey("credentials_file"): - return None - - super_gluu_creds_file = configurationAttributes.get("credentials_file").getValue2() - - # Load credentials from file - f = open(super_gluu_creds_file, 'r') - try: - creds = json.loads(f.read()) - except: - print "Super-Gluu. Initialize notification services. Failed to load credentials from file:", super_gluu_creds_file - return None - finally: - f.close() - - return creds - - def sendPushNotification(self, client_redirect_uri, user, super_gluu_request): - try: - self.sendPushNotificationImpl(client_redirect_uri, user, super_gluu_request) - except: - print "Super-Gluu. Send push notification. Failed to send push notification: ", sys.exc_info()[1] - - def sendPushNotificationImpl(self, client_redirect_uri, user, super_gluu_request): - if not self.enabledPushNotifications: - return - - user_name = user.getUserId() - print "Super-Gluu. Send push notification. Loading user '%s' devices" % user_name - - send_notification = False - send_notification_result = True - - userService = CdiUtil.bean(UserService) - deviceRegistrationService = CdiUtil.bean(DeviceRegistrationService) - - user_inum = userService.getUserInum(user_name) - - send_android = 0 - send_ios = 0 - u2f_devices_list = deviceRegistrationService.findUserDeviceRegistrations(user_inum, client_redirect_uri, "jansId", "jansDeviceData", "jansDeviceNotificationConf") - if u2f_devices_list.size() > 0: - for u2f_device in u2f_devices_list: - device_data = u2f_device.getDeviceData() - - # Device data which Super-Gluu gets during enrollment - if device_data == None: - continue - - platform = device_data.getPlatform() - push_token = device_data.getPushToken() - debug = False - - if StringHelper.equalsIgnoreCase(platform, "ios") and StringHelper.isNotEmpty(push_token): - # Sending notification to iOS user's device - if self.pushAppleService == None: - print "Super-Gluu. Send push notification. Apple native push notification service is not enabled" - else: - send_notification = True - - title = "Super Gluu" - message = "Confirm your sign in request to: %s" % client_redirect_uri - - if self.pushSnsMode or self.pushGluuMode: - pushSnsService = CdiUtil.bean(PushSnsService) - targetEndpointArn = self.getTargetEndpointArn(deviceRegistrationService, pushSnsService, PushPlatform.APNS, user, u2f_device) - if targetEndpointArn == None: - return - - send_notification = True - - sns_push_request_dictionary = { "aps": - { "badge": 0, - "alert" : {"body": message, "title" : title}, - "category": "ACTIONABLE", - "content-available": "1", - "sound": 'default' - }, - "request" : super_gluu_request - } - push_message = json.dumps(sns_push_request_dictionary, separators=(',',':')) - - if self.pushSnsMode: - apple_push_platform = PushPlatform.APNS - if not self.pushAppleServiceProduction: - apple_push_platform = PushPlatform.APNS_SANDBOX - - send_notification_result = pushSnsService.sendPushMessage(self.pushAppleService, apple_push_platform, targetEndpointArn, push_message, None) - if debug: - print "Super-Gluu. Send iOS SNS push notification. token: '%s', message: '%s', send_notification_result: '%s', apple_push_platform: '%s'" % (push_token, push_message, send_notification_result, apple_push_platform) - elif self.pushGluuMode: - send_notification_result = self.pushAppleService.sendNotification(self.pushAppleServiceAuth, targetEndpointArn, push_message) - if debug: - print "Super-Gluu. Send iOS Gluu push notification. token: '%s', message: '%s', send_notification_result: '%s'" % (push_token, push_message, send_notification_result) - else: - additional_fields = { "request" : super_gluu_request } - - msgBuilder = APNS.newPayload().alertBody(message).alertTitle(title).sound("default") - msgBuilder.category('ACTIONABLE').badge(0) - msgBuilder.forNewsstand() - msgBuilder.customFields(additional_fields) - push_message = msgBuilder.build() - - send_notification_result = self.pushAppleService.push(push_token, push_message) - if debug: - print "Super-Gluu. Send iOS Native push notification. token: '%s', message: '%s', send_notification_result: '%s'" % (push_token, push_message, send_notification_result) - send_ios = 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. Send native push notification. Android native push notification service is not enabled" - else: - send_notification = True - - title = "Super-Gluu" - if self.pushSnsMode or self.pushGluuMode: - pushSnsService = CdiUtil.bean(PushSnsService) - targetEndpointArn = self.getTargetEndpointArn(deviceRegistrationService, pushSnsService, PushPlatform.GCM, user, u2f_device) - if targetEndpointArn == None: - return - - send_notification = True - - sns_push_request_dictionary = { "collapse_key": "single", - "content_available": True, - "time_to_live": 60, - "data": - { "message" : super_gluu_request, - "title" : title } - } - push_message = json.dumps(sns_push_request_dictionary, separators=(',',':')) - - if self.pushSnsMode: - send_notification_result = pushSnsService.sendPushMessage(self.pushAndroidService, PushPlatform.GCM, targetEndpointArn, push_message, None) - if debug: - print "Super-Gluu. Send Android SNS push notification. token: '%s', message: '%s', send_notification_result: '%s'" % (push_token, push_message, send_notification_result) - elif self.pushGluuMode: - send_notification_result = self.pushAndroidService.sendNotification(self.pushAndroidServiceAuth, targetEndpointArn, push_message) - if debug: - print "Super-Gluu. Send Android Gluu push notification. token: '%s', message: '%s', send_notification_result: '%s'" % (push_token, push_message, send_notification_result) - else: - msgBuilder = Message.Builder().addData("message", super_gluu_request).addData("title", title).collapseKey("single").contentAvailable(True) - push_message = msgBuilder.build() - - send_notification_result = self.pushAndroidService.send(push_message, push_token, 3) - if debug: - print "Super-Gluu. Send Android Native push notification. token: '%s', message: '%s', send_notification_result: '%s'" % (push_token, push_message, send_notification_result) - send_android = send_android + 1 - - print "Super-Gluu. Send push notification. send_android: '%s', send_ios: '%s'" % (send_android, send_ios) - - def getTargetEndpointArn(self, deviceRegistrationService, pushSnsService, platform, user, u2fDevice): - targetEndpointArn = None - - # Return endpoint ARN if it created already - notificationConf = u2fDevice.getDeviceNotificationConf() - if StringHelper.isNotEmpty(notificationConf): - notificationConfJson = json.loads(notificationConf) - targetEndpointArn = notificationConfJson['sns_endpoint_arn'] - if StringHelper.isNotEmpty(targetEndpointArn): - print "Super-Gluu. Get target endpoint ARN. There is already created target endpoint ARN" - return targetEndpointArn - - # Create endpoint ARN - pushClient = None - pushClientAuth = None - platformApplicationArn = None - if platform == PushPlatform.GCM: - pushClient = self.pushAndroidService - if self.pushSnsMode: - platformApplicationArn = self.pushAndroidPlatformArn - if self.pushGluuMode: - pushClientAuth = self.pushAndroidServiceAuth - elif platform == PushPlatform.APNS: - pushClient = self.pushAppleService - if self.pushSnsMode: - platformApplicationArn = self.pushApplePlatformArn - if self.pushGluuMode: - pushClientAuth = self.pushAppleServiceAuth - else: - return None - - deviceData = u2fDevice.getDeviceData() - pushToken = deviceData.getPushToken() - - print "Super-Gluu. Get target endpoint ARN. Attempting to create target endpoint ARN for user: '%s'" % user.getUserId() - if self.pushSnsMode: - targetEndpointArn = pushSnsService.createPlatformArn(pushClient, platformApplicationArn, pushToken, user) - else: - customUserData = pushSnsService.getCustomUserData(user) - registerDeviceResponse = pushClient.registerDevice(pushClientAuth, pushToken, customUserData); - if registerDeviceResponse != None and registerDeviceResponse.getStatusCode() == 200: - targetEndpointArn = registerDeviceResponse.getEndpointArn() - - if StringHelper.isEmpty(targetEndpointArn): - print "Super-Gluu. Failed to get endpoint ARN for user: '%s'" % user.getUserId() - return None - - print "Super-Gluu. Get target endpoint ARN. Create target endpoint ARN '%s' for user: '%s'" % (targetEndpointArn, user.getUserId()) - - # Store created endpoint ARN in device entry - userInum = user.getAttribute("inum") - u2fDeviceUpdate = deviceRegistrationService.findUserDeviceRegistration(userInum, u2fDevice.getId()) - u2fDeviceUpdate.setDeviceNotificationConf('{"sns_endpoint_arn" : "%s"}' % targetEndpointArn) - deviceRegistrationService.updateDeviceRegistration(userInum, u2fDeviceUpdate) - - return targetEndpointArn - - def getApplicationUri(self, session_attributes): - if self.applicationId != None: - return self.applicationId - - if not session_attributes.containsKey("redirect_uri"): - return None - - return session_attributes.get("redirect_uri") - - def setRequestScopedParameters(self, identity, step): - downloadMap = HashMap() - if self.registrationUri != None: - identity.setWorkingParameter("external_registration_uri", self.registrationUri) - - if self.androidUrl!= None and step == 1: - downloadMap.put("android", self.androidUrl) - - if self.IOSUrl != None and step == 1: - downloadMap.put("ios", self.IOSUrl) - - if self.customLabel != None: - identity.setWorkingParameter("super_gluu_label", self.customLabel) - - identity.setWorkingParameter("download_url", downloadMap) - identity.setWorkingParameter("super_gluu_qr_options", self.customQrOptions) - - def addGeolocationData(self, session_attributes, super_gluu_request_dictionary): - if session_attributes.containsKey("remote_ip"): - remote_ip = session_attributes.get("remote_ip") - if StringHelper.isNotEmpty(remote_ip): - print "Super-Gluu. Prepare for step 2. Adding req_ip and req_loc to super_gluu_request" - super_gluu_request_dictionary['req_ip'] = remote_ip - - remote_loc_dic = self.determineGeolocationData(remote_ip) - if remote_loc_dic == None: - print "Super-Gluu. Prepare for step 2. Failed to determine remote location by remote IP '%s'" % remote_ip - return - - remote_loc = "%s, %s, %s" % ( remote_loc_dic['country'], remote_loc_dic['regionName'], remote_loc_dic['city'] ) - remote_loc_encoded = urllib.quote(remote_loc.encode('utf-8')) - super_gluu_request_dictionary['req_loc'] = remote_loc_encoded - - def determineGeolocationData(self, remote_ip): - print "Super-Gluu. Determine remote location. remote_ip: '%s'" % remote_ip - httpService = CdiUtil.bean(HttpService) - - http_client = httpService.getHttpsClient() - http_client_params = http_client.getParams() - http_client_params.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 15 * 1000) - - geolocation_service_url = "http://ip-api.com/json/%s?fields=49177" % 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 "Super-Gluu. Determine remote location. Exception: ", sys.exc_info()[1] - return None - - try: - if not httpService.isResponseStastusCodeOk(http_response): - print "Super-Gluu. Determine remote location. Get invalid response from validation server: ", 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) - finally: - http_service_response.closeConnection() - - if response_string == None: - print "Super-Gluu. Determine remote location. Get empty response from location server" - return None - - response = json.loads(response_string) - - if not StringHelper.equalsIgnoreCase(response['status'], "success"): - print "Super-Gluu. Determine remote location. Get response with status: '%s'" % response['status'] - return None - - return response - - 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 processAuditGroup(self, user, attribute, group): - is_member = self.isUserMemberOfGroup(user, attribute, group) - if (is_member): - print "Super-Gluu. Authenticate for processAuditGroup. User '%s' member of audit group" % user.getUserId() - print "Super-Gluu. Authenticate for processAuditGroup. Sending e-mail about user '%s' login to %s" % (user.getUserId(), self.audit_email) - - # Send e-mail to administrator - user_id = user.getUserId() - mailService = CdiUtil.bean(MailService) - subject = "User log in: %s" % user_id - body = "User log in: %s" % user_id - mailService.sendMail(self.audit_email, subject, body) diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/UserCertExternalAuthenticator.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/UserCertExternalAuthenticator.py deleted file mode 100644 index 2f5632bf4a0..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/UserCertExternalAuthenticator.py +++ /dev/null @@ -1,485 +0,0 @@ -# -# Janssen Project software is available under the Apache 2.0 License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Yuriy Movchan -# - -from io.jans.service.cdi.util import CdiUtil -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from jakarta.faces.context import FacesContext -from io.jans.as.server.security import Identity -from io.jans.as.server.service import AuthenticationService -from io.jans.as.server.service import UserService -from io.jans.util import StringHelper -from io.jans.as.server.util import ServerUtil -from io.jans.as.common.service.common import EncryptionService -from java.util import Arrays -from io.jans.as.common.cert.fingerprint import FingerprintHelper -from io.jans.as.common.cert.validation import GenericCertificateVerifier -from io.jans.as.common.cert.validation import PathCertificateVerifier -from io.jans.as.common.cert.validation import OCSPCertificateVerifier -from io.jans.as.common.cert.validation import CRLCertificateVerifier -from io.jans.as.common.cert.validation.model import ValidationStatus -from io.jans.as.server.util import CertUtil -from io.jans.as.model.util import CertUtils -from io.jans.as.server.service.net import HttpService -from org.apache.http.params import CoreConnectionPNames - -import sys -import base64 -import urllib - -import java -import json - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, 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 destroy(self, configurationAttributes): - print "Cert. Destroy" - - for type in self.validator_types: - self.validators[type][0].destroy() - - print "Cert. Destroyed successfully" - - return True - - def getApiVersion(self): - return 11 - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - def authenticate(self, configurationAttributes, requestParameters, step): - identity = CdiUtil.bean(Identity) - credentials = identity.getCredentials() - - user_name = credentials.getUsername() - - userService = CdiUtil.bean(UserService) - authenticationService = CdiUtil.bean(AuthenticationService) - - if step == 1: - print "Cert. Authenticate for step 1" - login_button = ServerUtil.getFirstValue(requestParameters, "loginForm:loginButton") - if StringHelper.isEmpty(login_button): - print "Cert. Authenticate for step 1. Form were submitted incorrectly" - return False - if self.enabled_recaptcha: - print "Cert. Authenticate for step 1. Validating recaptcha response" - recaptcha_response = ServerUtil.getFirstValue(requestParameters, "g-recaptcha-response") - - recaptcha_result = self.validateRecaptcha(recaptcha_response) - print "Cert. Authenticate for step 1. recaptcha_result: '%s'" % recaptcha_result - - return recaptcha_result - - return True - elif step == 2: - print "Cert. Authenticate for step 2" - - # Validate if user selected certificate - cert_x509 = self.getSessionAttribute("cert_x509") - if cert_x509 == None: - print "Cert. Authenticate for step 2. User not selected any certs" - identity.setWorkingParameter("cert_selected", False) - - # Return True to inform user how to reset workflow - return True - else: - identity.setWorkingParameter("cert_selected", True) - x509Certificate = self.certFromString(cert_x509) - - subjectX500Principal = x509Certificate.getSubjectX500Principal() - print "Cert. Authenticate for step 2. User selected certificate with DN '%s'" % subjectX500Principal - - # Validate certificates which user selected - valid = self.validateCertificate(x509Certificate) - if not valid: - print "Cert. Authenticate for step 2. Certificate DN '%s' is not valid" % subjectX500Principal - identity.setWorkingParameter("cert_valid", False) - - # Return True to inform user how to reset workflow - return True - - identity.setWorkingParameter("cert_valid", True) - - # Calculate certificate fingerprint - x509CertificateFingerprint = self.calculateCertificateFingerprint(x509Certificate) - identity.setWorkingParameter("cert_x509_fingerprint", x509CertificateFingerprint) - print "Cert. Authenticate for step 2. Fingerprint is '%s' of certificate with DN '%s'" % (x509CertificateFingerprint, subjectX500Principal) - - # Attempt to find user by certificate fingerprint - cert_user_external_uid = "cert:%s" % x509CertificateFingerprint - print "Cert. Authenticate for step 2. Attempting to find user by jansExtUid attribute value %s" % cert_user_external_uid - - find_user_by_external_uid = userService.getUserByAttribute("jansExtUid", cert_user_external_uid) - if find_user_by_external_uid == None: - print "Cert. Authenticate for step 2. Failed to find user" - - if self.map_user_cert: - print "Cert. Authenticate for step 2. Storing cert_user_external_uid for step 3" - identity.setWorkingParameter("cert_user_external_uid", cert_user_external_uid) - return True - else: - print "Cert. Authenticate for step 2. Mapping cert to user account is not allowed" - identity.setWorkingParameter("cert_count_login_steps", 2) - return False - - foundUserName = find_user_by_external_uid.getUserId() - print "Cert. Authenticate for step 2. foundUserName: " + foundUserName - - logged_in = False - userService = CdiUtil.bean(UserService) - logged_in = authenticationService.authenticate(foundUserName) - - print "Cert. Authenticate for step 2. Setting count steps to 2" - identity.setWorkingParameter("cert_count_login_steps", 2) - - return logged_in - elif step == 3: - print "Cert. Authenticate for step 3" - - cert_user_external_uid = self.getSessionAttribute("cert_user_external_uid") - if cert_user_external_uid == None: - print "Cert. Authenticate for step 3. cert_user_external_uid is empty" - return False - - 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 - - # Double check just to make sure. We did checking in previous step - # Check if there is user which has cert_user_external_uid - # Avoid mapping user cert to more than one IDP account - find_user_by_external_uid = userService.getUserByAttribute("jansExtUid", cert_user_external_uid) - if find_user_by_external_uid == None: - # Add cert_user_external_uid to user's external GUID list - find_user_by_external_uid = userService.addUserAttribute(user_name, "jansExtUid", cert_user_external_uid) - if find_user_by_external_uid == None: - print "Cert. Authenticate for step 3. Failed to update current user" - return False - - return True - - return True - else: - return False - - def prepareForStep(self, configurationAttributes, requestParameters, step): - print "Cert. Prepare for step %d" % step - identity = CdiUtil.bean(Identity) - - if step == 1: - if self.enabled_recaptcha: - identity.setWorkingParameter("recaptcha_site_key", self.recaptcha_creds['site_key']) - elif step == 2: - # Store certificate in session - facesContext = CdiUtil.bean(FacesContext) - externalContext = facesContext.getExternalContext() - request = externalContext.getRequest() - - # Try to get certificate from header X-ClientCert - clientCertificate = externalContext.getRequestHeaderMap().get("X-ClientCert") - if clientCertificate != None: - x509Certificate = self.certFromPemString(clientCertificate) - identity.setWorkingParameter("cert_x509", self.certToString(x509Certificate)) - print "Cert. Prepare for step 2. Storing user certificate obtained from 'X-ClientCert' header" - return True - - # Try to get certificate from attribute jakarta.servlet.request.X509Certificate - x509Certificates = request.getAttribute('jakarta.servlet.request.X509Certificate') - if (x509Certificates != None) and (len(x509Certificates) > 0): - identity.setWorkingParameter("cert_x509", self.certToString(x509Certificates[0])) - print "Cert. Prepare for step 2. Storing user certificate obtained from 'jakarta.servlet.request.X509Certificate' attribute" - return True - - if step < 4: - return True - else: - return False - - def getExtraParametersForStep(self, configurationAttributes, step): - return Arrays.asList("cert_selected", "cert_valid", "cert_x509", "cert_x509_fingerprint", "cert_count_login_steps", "cert_user_external_uid") - - def getCountAuthenticationSteps(self, configurationAttributes): - cert_count_login_steps = self.getSessionAttribute("cert_count_login_steps") - if cert_count_login_steps != None: - return cert_count_login_steps - else: - return 3 - - def getPageForStep(self, configurationAttributes, step): - if step == 1: - return "/auth/cert/login.xhtml" - if step == 2: - return "/auth/cert/cert-login.xhtml" - elif step == 3: - cert_selected = self.getSessionAttribute("cert_selected") - if True != cert_selected: - return "/auth/cert/cert-not-selected.xhtml" - - cert_valid = self.getSessionAttribute("cert_valid") - if True != cert_valid: - return "/auth/cert/cert-invalid.xhtml" - - return "/login.xhtml" - - return "" - - def logout(self, configurationAttributes, requestParameters): - return True - - 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 "Cert. Process basic authentication. Failed to find user '%s'" % user_name - return None - - return find_user_by_uid - - def getSessionAttribute(self, attribute_name): - identity = CdiUtil.bean(Identity) - - # Try to get attribute value from Seam event context - if identity.isSetWorkingParameter(attribute_name): - return identity.getWorkingParameter(attribute_name) - - # Try to get attribute from persistent session - session_id = identity.getSessionId() - if session_id == None: - return None - - session_attributes = session_id.getSessionAttributes() - if session_attributes == None: - return None - - if session_attributes.containsKey(attribute_name): - return session_attributes.get(attribute_name) - - return None - - def calculateCertificateFingerprint(self, x509Certificate): - print "Cert. Calculate fingerprint for certificate DN '%s'" % x509Certificate.getSubjectX500Principal() - - publicKey = x509Certificate.getPublicKey() - - # Use oxAuth implementation - fingerprint = FingerprintHelper.getPublicKeySshFingerprint(publicKey) - - return fingerprint - - def validateCertificate(self, x509Certificate): - subjectX500Principal = x509Certificate.getSubjectX500Principal() - - print "Cert. Validating certificate with DN '%s'" % subjectX500Principal - - validation_date = java.util.Date() - - for type in self.validator_types: - if self.validators[type][1]: - result = self.validators[type][0].validate(x509Certificate, self.chain_certs, validation_date) - print "Cert. Validate certificate: '%s'. Validation method '%s' result: '%s'" % (subjectX500Principal, type, result) - - if (result.getValidity() != ValidationStatus.CertificateValidity.VALID): - print "Cert. Certificate: '%s' is invalid" % subjectX500Principal - return False - - return True - - def certToString(self, x509Certificate): - if x509Certificate == None: - return None - return base64.b64encode(x509Certificate.getEncoded()) - - def certFromString(self, x509CertificateEncoded): - x509CertificateDecoded = base64.b64decode(x509CertificateEncoded) - return CertUtils.x509CertificateFromBytes(x509CertificateDecoded) - - def certFromPemString(self, pemCertificate): - x509CertificateEncoded = pemCertificate.replace("-----BEGIN CERTIFICATE-----", "").replace("-----END CERTIFICATE-----", "").strip() - return self.certFromString(x509CertificateEncoded) - - def initRecaptcha(self, configurationAttributes): - print "Cert. Initialize recaptcha" - if not configurationAttributes.containsKey("credentials_file"): - return False - - cert_creds_file = configurationAttributes.get("credentials_file").getValue2() - - # Load credentials from file - f = open(cert_creds_file, 'r') - try: - creds = json.loads(f.read()) - except: - print "Cert. Initialize recaptcha. Failed to load credentials from file: %s" % cert_creds_file - return False - finally: - f.close() - - try: - recaptcha_creds = creds["recaptcha"] - except: - print "Cert. Initialize recaptcha. Invalid credentials file '%s' format:" % cert_creds_file - return False - - self.recaptcha_creds = None - if recaptcha_creds["enabled"]: - print "Cert. Initialize recaptcha. Recaptcha is enabled" - - encryptionService = CdiUtil.bean(EncryptionService) - - site_key = recaptcha_creds["site_key"] - secret_key = recaptcha_creds["secret_key"] - - try: - site_key = encryptionService.decrypt(site_key) - except: - # Ignore exception. Value is not encrypted - print "Cert. Initialize recaptcha. Assuming that 'site_key' in not encrypted" - - try: - secret_key = encryptionService.decrypt(secret_key) - except: - # Ignore exception. Value is not encrypted - print "Cert. Initialize recaptcha. Assuming that 'secret_key' in not encrypted" - - - self.recaptcha_creds = { 'site_key' : site_key, "secret_key" : secret_key } - print "Cert. Initialize recaptcha. Recaptcha is configured correctly" - - return True - else: - print "Cert. Initialize recaptcha. Recaptcha is disabled" - - return False - - def validateRecaptcha(self, recaptcha_response): - print "Cert. Validate recaptcha response" - - facesContext = CdiUtil.bean(FacesContext) - request = facesContext.getExternalContext().getRequest() - - remoteip = ServerUtil.getIpAddress(request) - print "Cert. Validate recaptcha response. remoteip: '%s'" % remoteip - - httpService = CdiUtil.bean(HttpService) - - http_client = httpService.getHttpsClient() - http_client_params = http_client.getParams() - http_client_params.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 15 * 1000) - - recaptcha_validation_url = "https://www.google.com/recaptcha/api/siteverify" - recaptcha_validation_request = urllib.urlencode({ "secret" : self.recaptcha_creds['secret_key'], "response" : recaptcha_response, "remoteip" : remoteip }) - recaptcha_validation_headers = { "Content-type" : "application/x-www-form-urlencoded", "Accept" : "application/json" } - - try: - http_service_response = httpService.executePost(http_client, recaptcha_validation_url, None, recaptcha_validation_headers, recaptcha_validation_request) - http_response = http_service_response.getHttpResponse() - except: - print "Cert. Validate recaptcha response. Exception: ", sys.exc_info()[1] - return False - - try: - if not httpService.isResponseStastusCodeOk(http_response): - print "Cert. Validate recaptcha response. Get invalid response from validation server: ", str(http_response.getStatusLine().getStatusCode()) - httpService.consume(http_response) - return False - - response_bytes = httpService.getResponseContent(http_response) - response_string = httpService.convertEntityToString(response_bytes) - httpService.consume(http_response) - finally: - http_service_response.closeConnection() - - if response_string == None: - print "Cert. Validate recaptcha response. Get empty response from validation server" - return False - - response = json.loads(response_string) - - return response["success"] - - def getNextStep(self, configurationAttributes, requestParameters, step): - return -1 - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Get external logout URL call" - return None \ No newline at end of file diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/YubicloudExternalAuthenticator.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/YubicloudExternalAuthenticator.py deleted file mode 100644 index ada83ef1457..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/YubicloudExternalAuthenticator.py +++ /dev/null @@ -1,118 +0,0 @@ -# Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Yuriy Movchan, Arunmozhi -# - -from io.jans.service.cdi.util import CdiUtil -from io.jans.as.server.security import Identity -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.as.server.service import UserService -from io.jans.util import StringHelper - -import java - -import urllib2 -import urllib -import uuid - - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - print "Yubicloud. Initialization" - - self.api_server = configurationAttributes.get("yubicloud_uri").getValue2() - self.api_key = configurationAttributes.get("yubicloud_api_key").getValue2() - self.client_id = configurationAttributes.get("yubicloud_id").getValue2() - - return True - - def destroy(self, configurationAttributes): - print "Yubicloud. Destroyed successfully" - return True - - def getApiVersion(self): - return 11 - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - def authenticate(self, configurationAttributes, requestParameters, step): - if (step == 1): - print "Yubicloud. Authenticate for step 1" - - identity = CdiUtil.bean(Identity) - credentials = identity.getCredentials() - - username = credentials.getUsername() - otp = credentials.getPassword() - - # Validate otp length - if len(otp) < 32 or len(otp) > 48: - print "Yubicloud. Invalid OTP length" - return False - - user_service = CdiUtil.bean(UserService) - user = user_service.getUser(username) - - public_key = user.getAttribute('yubikeyId') - - # Match the user with the yubikey - if public_key not in otp: - print "Yubicloud. Public Key not matching OTP" - return False - - data = "" - try: - nonce = str(uuid.uuid4()).replace("-", "") - params = urllib.urlencode({"id": self.client_id, "otp": otp, "nonce": nonce}) - url = "https://" + self.api_server + "/wsapi/2.0/verify/?" + params - f = urllib2.urlopen(url) - data = f.read() - except Exception as e: - print "Yubicloud. Exception ", e - - if 'status=OK' in data: - user_service.authenticate(username) - print "Yubicloud. Authentication Successful" - return True - - print "Yubicloud. End of Step 1. Returning False." - return False - else: - return False - - def prepareForStep(self, configurationAttributes, requestParameters, step): - if (step == 1): - print "Yubicloud. Prepare for Step 1" - return True - else: - return False - - def getExtraParametersForStep(self, configurationAttributes, step): - return None - - def getCountAuthenticationSteps(self, configurationAttributes): - return 1 - - def getPageForStep(self, configurationAttributes, step): - return "" - - def getNextStep(self, configurationAttributes, requestParameters, step): - return -1 - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Get external logout URL call" - return None - - def logout(self, configurationAttributes, requestParameters): - return True diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/smpp2FA.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/smpp2FA.py deleted file mode 100644 index 31eca546f20..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/smpp2FA.py +++ /dev/null @@ -1,435 +0,0 @@ -# Janssen Project software is available under the Apache 2.0 License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# Copyright (c) 2019, Tele2 - -# Author: Jose Gonzalez -# Author: Gasmyr Mougang -# Author: Stefan Andersson - -from java.util import Arrays, Date -from java.io import IOException -from java.lang import Enum - -from io.jans.service.cdi.util import CdiUtil -from io.jans.as.server.security import Identity -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.as.server.service import AuthenticationService -from io.jans.as.server.service import UserService -from io.jans.as.server.util import ServerUtil -from io.jans.util import ArrayHelper -from io.jans.util import StringHelper -from jakarta.faces.application import FacesMessage -from io.jans.jsf2.message import FacesMessages - -from org.jsmpp import InvalidResponseException, PDUException -from org.jsmpp.bean import Alphabet, BindType, ESMClass, GeneralDataCoding, MessageClass, NumberingPlanIndicator, RegisteredDelivery, SMSCDeliveryReceipt, TypeOfNumber -from org.jsmpp.extra import NegativeResponseException, ResponseTimeoutException -from org.jsmpp.session import BindParameter, SMPPSession -from org.jsmpp.util import AbsoluteTimeFormatter, TimeFormatter -import random - - -class SmppAttributeError(Exception): - pass - - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - self.identity = CdiUtil.bean(Identity) - - def get_and_parse_smpp_config(self, config, attribute, _type = None, convert = False, optional = False, default_desc = None): - try: - value = config.get(attribute).getValue2() - except: - if default_desc: - default_desc = " using default '{}'".format(default_desc) - else: - default_desc = "" - - if optional: - raise SmppAttributeError("SMPP missing optional configuration attribute '{}'{}".format(attribute, default_desc)) - else: - raise SmppAttributeError("SMPP missing required configuration attribute '{}'".format(attribute)) - - if _type and issubclass(_type, Enum): - try: - return getattr(_type, value) - except AttributeError: - raise SmppAttributeError("SMPP could not find attribute '{}' in {}".format(attribute, _type)) - - if convert: - try: - value = int(value) - except AttributeError: - try: - value = int(value, 16) - except AttributeError: - raise SmppAttributeError("SMPP could not parse value '{}' of attribute '{}'".format(value, attribute)) - - return value - - def init(self, customScript, configurationAttributes): - print("SMPP Initialization") - - self.TIME_FORMATTER = AbsoluteTimeFormatter() - - self.SMPP_SERVER = None - self.SMPP_PORT = None - - self.SYSTEM_ID = None - self.PASSWORD = None - - # Setup some good defaults for TON, NPI and source (from) address - # TON (Type of Number), NPI (Number Plan Indicator) - self.SRC_ADDR_TON = TypeOfNumber.ALPHANUMERIC # Alphanumeric - self.SRC_ADDR_NPI = NumberingPlanIndicator.ISDN # ISDN (E163/E164) - self.SRC_ADDR = "Janssen OTP" - - # Don't touch these unless you know what your doing, we don't handle number reformatting for - # any other type than international. - self.DST_ADDR_TON = TypeOfNumber.INTERNATIONAL # International - self.DST_ADDR_NPI = NumberingPlanIndicator.ISDN # ISDN (E163/E164) - - # Priority flag and data_coding bits - self.PRIORITY_FLAG = 3 # Very Urgent (ANSI-136), Emergency (IS-95) - self.DATA_CODING_ALPHABET = Alphabet.ALPHA_DEFAULT # SMS default alphabet - self.DATA_CODING_MESSAGE_CLASS = MessageClass.CLASS1 # EM (Mobile Equipment (mobile memory), normal message - - # Required server settings - try: - self.SMPP_SERVER = self.get_and_parse_smpp_config(configurationAttributes, "smpp_server") - except SmppAttributeError as e: - print(e) - - try: - self.SMPP_PORT = self.get_and_parse_smpp_config(configurationAttributes, "smpp_port", convert = True) - except SmppAttributeError as e: - print(e) - - if None in (self.SMPP_SERVER, self.SMPP_PORT): - print("SMPP smpp_server and smpp_port is empty, will not enable SMPP service") - return False - - # Optional system_id and password for bind auth - try: - self.SYSTEM_ID = self.get_and_parse_smpp_config(configurationAttributes, "system_id", optional = True) - except SmppAttributeError as e: - print(e) - - try: - self.PASSWORD = self.get_and_parse_smpp_config(configurationAttributes, "password", optional = True) - except SmppAttributeError as e: - print(e) - - if None in (self.SYSTEM_ID, self.PASSWORD): - print("SMPP Authentication disabled") - - # From number and to number settings - try: - self.SRC_ADDR_TON = self.get_and_parse_smpp_config( - configurationAttributes, - "source_addr_ton", - _type = TypeOfNumber, - optional = True, - default_desc = self.SRC_ADDR_TON - ) - except SmppAttributeError as e: - print(e) - - try: - self.SRC_ADDR_NPI = self.get_and_parse_smpp_config( - configurationAttributes, - "source_addr_npi", - _type = NumberingPlanIndicator, - optional = True, - default_desc = self.SRC_ADDR_NPI - ) - except SmppAttributeError as e: - print(e) - - try: - self.SRC_ADDR = self.get_and_parse_smpp_config( - configurationAttributes, - "source_addr", - optional = True, - default_desc = self.SRC_ADDR - ) - except SmppAttributeError as e: - print(e) - - try: - self.DST_ADDR_TON = self.get_and_parse_smpp_config( - configurationAttributes, - "dest_addr_ton", - _type = TypeOfNumber, - optional = True, - default_desc = self.DST_ADDR_TON - ) - except SmppAttributeError as e: - print(e) - - try: - self.DST_ADDR_NPI = self.get_and_parse_smpp_config( - configurationAttributes, - "dest_addr_npi", - _type = NumberingPlanIndicator, - optional = True, - default_desc = self.DST_ADDR_NPI - ) - except SmppAttributeError as e: - print(e) - - # Priority flag and data coding, don't touch these unless you know what your doing... - try: - self.PRIORITY_FLAG = self.get_and_parse_smpp_config( - configurationAttributes, - "priority_flag", - convert = True, - optional = True, - default_desc = "3 (Very Urgent, Emergency)" - ) - except SmppAttributeError as e: - print(e) - - try: - self.DATA_CODING_ALPHABET = self.get_and_parse_smpp_config( - configurationAttributes, - "data_coding_alphabet", - _type = Alphabet, - optional = True, - default_desc = self.DATA_CODING_ALPHABET - ) - except SmppAttributeError as e: - print(e) - - try: - self.DATA_CODING_MESSAGE_CLASS = self.get_and_parse_smpp_config( - configurationAttributes, - "data_coding_alphabet", - _type = MessageClass, - optional = True, - default_desc = self.DATA_CODING_MESSAGE_CLASS - ) - except SmppAttributeError as e: - print(e) - - print("SMPP Initialized successfully") - return True - - def destroy(self, configurationAttributes): - print("SMPP Destroy") - print("SMPP Destroyed successfully") - return True - - def getApiVersion(self): - return 11 - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - 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): - if step == 1: - print("SMPP Prepare for Step 1") - return True - elif step == 2: - print("SMPP Prepare for Step 2") - return True - - return False - - def getExtraParametersForStep(self, configurationAttributes, step): - if step == 2: - return Arrays.asList("code") - - return None - - def getCountAuthenticationSteps(self, configurationAttributes): - return 2 - - def getPageForStep(self, configurationAttributes, step): - if step == 2: - return "/auth/otp_sms/otp_sms.xhtml" - - return "" - - def getNextStep(self, configurationAttributes, requestParameters, step): - return -1 - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Get external logout URL call" - return None - - def logout(self, configurationAttributes, requestParameters): - return True - - def sendMessage(self, number, code): - status = False - session = SMPPSession() - session.setTransactionTimer(10000) - - # We only handle international destination number reformatting. - # All others may vary by configuration decisions taken on SMPP - # server side which we have no clue about. - if self.DST_ADDR_TON == TypeOfNumber.INTERNATIONAL and number.startswith("+"): - number = number[1:] - - try: - print("SMPP Connecting") - reference_id = session.connectAndBind( - self.SMPP_SERVER, - self.SMPP_PORT, - BindParameter( - BindType.BIND_TX, - self.SYSTEM_ID, - self.PASSWORD, - None, - self.SRC_ADDR_TON, - self.SRC_ADDR_NPI, - None - ) - ) - print("SMPP Connected to server with system id {}".format(reference_id)) - - try: - message_id = session.submitShortMessage( - "CMT", - self.SRC_ADDR_TON, - self.SRC_ADDR_NPI, - self.SRC_ADDR, - self.DST_ADDR_TON, - self.DST_ADDR_NPI, - number, - ESMClass(), - 0, - self.PRIORITY_FLAG, - self.TIME_FORMATTER.format(Date()), - None, - RegisteredDelivery(SMSCDeliveryReceipt.DEFAULT), - 0, - GeneralDataCoding( - self.DATA_CODING_ALPHABET, - self.DATA_CODING_MESSAGE_CLASS, - False - ), - 0, - code - ) - print("SMPP Message '{}' sent to #{} with message id {}".format(code, number, message_id)) - status = True - except PDUException as e: - print("SMPP Invalid PDU parameter: {}".format(e)) - except ResponseTimeoutException as e: - print("SMPP Response timeout: {}".format(e)) - except InvalidResponseException as e: - print("SMPP Receive invalid response: {}".format(e)) - except NegativeResponseException as e: - print("SMPP Receive negative response: {}".format(e)) - except IOException as e: - print("SMPP IO error occured: {}".format(e)) - finally: - session.unbindAndClose() - except IOException as e: - print("SMPP Failed connect and bind to host: {}".format(e)) - - return status diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/twilio2FA.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/twilio2FA.py deleted file mode 100644 index 3f0afc9d997..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/twilio2FA.py +++ /dev/null @@ -1,251 +0,0 @@ -# Janssen Project software is available under the Apache 2.0 License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Gasmyr Mougang - -from io.jans.service.cdi.util import CdiUtil -from io.jans.as.server.security import Identity -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.as.server.service import AuthenticationService -from io.jans.as.server.service import UserService -from io.jans.as.server.service import SessionIdService -from io.jans.as.server.util import ServerUtil -from io.jans.util import StringHelper -from io.jans.util import ArrayHelper -from java.util import Arrays -from jakarta.faces.application import FacesMessage -from io.jans.jsf2.message import FacesMessages - -import com.twilio.Twilio as Twilio -import com.twilio.rest.api.v2010.account.Message as Message -import com.twilio.type.PhoneNumber as PhoneNumber -import org.codehaus.jettison.json.JSONArray as JSONArray - - -import java -import random -import jarray - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - self.mobile_number = None - self.identity = CdiUtil.bean(Identity) - - def init(self, customScript, configurationAttributes): - print "==============================================" - print "===TWILIO SMS INITIALIZATION==================" - print "==============================================" - self.ACCOUNT_SID = None - self.AUTH_TOKEN = None - self.FROM_NUMBER = None - - # Get Custom Properties - try: - self.ACCOUNT_SID = configurationAttributes.get("twilio_sid").getValue2() - except: - print 'TwilioSMS, Missing required configuration attribute "twilio_sid"' - - try: - self.AUTH_TOKEN = configurationAttributes.get("twilio_token").getValue2() - except: - print'TwilioSMS, Missing required configuration attribute "twilio_token"' - try: - self.FROM_NUMBER = configurationAttributes.get("from_number").getValue2() - except: - print'TwilioSMS, Missing required configuration attribute "from_number"' - - if None in (self.ACCOUNT_SID, self.AUTH_TOKEN, self.FROM_NUMBER): - print "twilio_sid, twilio_token, from_number is empty ... returning False" - return False - - print "===TWILIO SMS INITIALIZATION DONE PROPERLY=====" - return True - - def destroy(self, configurationAttributes): - print "Twilio SMS. Destroy" - print "Twilio SMS. Destroyed successfully" - return True - - def getApiVersion(self): - return 11 - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - def authenticate(self, configurationAttributes, requestParameters, step): - print "==============================================" - print "====TWILIO SMS AUTHENCATION===================" - print "==============================================" - userService = CdiUtil.bean(UserService) - authenticationService = CdiUtil.bean(AuthenticationService) - sessionIdService = CdiUtil.bean(SessionIdService) - facesMessages = CdiUtil.bean(FacesMessages) - facesMessages.setKeepMessages() - - session_attributes = self.identity.getSessionId().getSessionAttributes() - form_passcode = ServerUtil.getFirstValue(requestParameters, "passcode") - form_name = ServerUtil.getFirstValue(requestParameters, "TwilioSmsloginForm") - - print "TwilioSMS. form_response_passcode: %s" % str(form_passcode) - - if step == 1: - print "==============================================" - print "=TWILIO SMS STEP 1 | Password Authentication==" - print "==============================================" - 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 'TwilioSMS, Error retrieving user %s from LDAP' % (user_name) - return False - - try: - isVerified = foundUser.getAttribute("phoneNumberVerified") - if isVerified: - self.mobile_number = foundUser.getAttribute("employeeNumber") - if self.mobile_number == None: - self.mobile_number = foundUser.getAttribute("mobile") - if self.mobile_number == None: - self.mobile_number = foundUser.getAttribute("telephoneNumber") - if self.mobile_number == None: - print "TwilioSMS, Error finding mobile number for user '%s'" % user_name - - except: - facesMessages.add(FacesMessage.SEVERITY_ERROR, "Failed to determine mobile phone number") - print 'TwilioSMS, Error finding mobile number for "%s". Exception: %s` % (user_name, sys.exc_info()[1])`' - return False - - # Generate Random six digit code and store it in array - code = random.randint(100000, 999999) - - # Get code and save it in LDAP temporarily with special session entry - self.identity.setWorkingParameter("code", code) - sessionId = sessionIdService.getSessionId() # fetch from persistence - sessionId.getSessionAttributes().put("code", code) - - try: - Twilio.init(self.ACCOUNT_SID, self.AUTH_TOKEN); - message = Message.creator(PhoneNumber(self.mobile_number), PhoneNumber(self.FROM_NUMBER), str(code)).create(); - print "++++++++++++++++++++++++++++++++++++++++++++++" - print 'TwilioSMs, Message Sid: %s' % (message.getSid()) - print 'TwilioSMs, User phone: %s' % (self.mobile_number) - print "++++++++++++++++++++++++++++++++++++++++++++++" - sessionId.getSessionAttributes().put("mobile_number", self.mobile_number) - sessionId.getSessionAttributes().put("mobile", self.mobile_number) - sessionIdService.updateSessionId(sessionId) - self.identity.setWorkingParameter("mobile_number", self.mobile_number) - self.identity.getSessionId().getSessionAttributes().put("mobile_number",self.mobile_number) - self.identity.setWorkingParameter("mobile", self.mobile_number) - self.identity.getSessionId().getSessionAttributes().put("mobile",self.mobile_number) - print "++++++++++++++++++++++++++++++++++++++++++++++" - print "Number: %s" % (self.identity.getWorkingParameter("mobile_number")) - print "Mobile: %s" % (self.identity.getWorkingParameter("mobile")) - print "++++++++++++++++++++++++++++++++++++++++++++++" - print "========================================" - print "===TWILIO SMS FIRST STEP DONE PROPERLY==" - print "========================================" - return True - except Exception, ex: - facesMessages.add(FacesMessage.SEVERITY_ERROR, "Failed to send message to mobile phone") - print "TwilioSMS. Error sending message to Twilio" - print "TwilioSMS. Unexpected error:", ex - - return False - elif step == 2: - # Retrieve the session attribute - print "==============================================" - print "=TWILIO SMS STEP 2 | Password Authentication==" - print "==============================================" - code = session_attributes.get("code") - print '=======> Session code is "%s"' % str(code) - sessionIdService = CdiUtil.bean(SessionIdService) - sessionId = sessionIdService.getSessionId() # fetch from persistence - code = sessionId.getSessionAttributes().get("code") - print '=======> Database code is "%s"' % str(code) - self.identity.setSessionId(sessionId) - print "==============================================" - print "TwilioSMS. Code: %s" % str(code) - print "==============================================" - if code is None: - print "TwilioSMS. Failed to find previously sent code" - return False - - if form_passcode is None: - print "TwilioSMS. Passcode is empty" - return False - - if len(form_passcode) != 6: - print "TwilioSMS. Passcode from response is not 6 digits: %s" % form_passcode - return False - - if form_passcode == code: - print "TiwlioSMS, SUCCESS! User entered the same code!" - print "========================================" - print "===TWILIO SMS SECOND STEP DONE PROPERLY" - print "========================================" - return True - - print "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" - print "TwilioSMS. FAIL! User entered the wrong code! %s != %s" % (form_passcode, code) - print "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" - facesMessages.add(FacesMessage.SEVERITY_ERROR, "Incorrect Twilio code, please try again.") - print "================================================" - print "===TWILIO SMS SECOND STEP FAILED: INCORRECT CODE" - print "================================================" - return False - - print "TwilioSMS. ERROR: step param not found or != (1|2)" - - return False - - def prepareForStep(self, configurationAttributes, requestParameters, step): - if step == 1: - print "TwilioSMS. Prepare for Step 1" - return True - elif step == 2: - print "TwilioSMS. Prepare for Step 2" - return True - return False - - def getExtraParametersForStep(self, configurationAttributes, step): - if step == 2: - return Arrays.asList("code") - - return None - - def getCountAuthenticationSteps(self, configurationAttributes): - return 2 - - def getPageForStep(self, configurationAttributes, step): - if step == 2: - return "/auth/otp_sms/otp_sms.xhtml" - - return "" - - def getNextStep(self, configurationAttributes, requestParameters, step): - return -1 - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Get external logout URL call" - return None - - def logout(self, configurationAttributes, requestParameters): - return True diff --git a/jans-linux-setup/jans_setup/templates/scripts.ldif b/jans-linux-setup/jans_setup/templates/scripts.ldif index 42a5febcdfd..2500de9a00c 100644 --- a/jans-linux-setup/jans_setup/templates/scripts.ldif +++ b/jans-linux-setup/jans_setup/templates/scripts.ldif @@ -14,7 +14,7 @@ jansLevel: 30 jansModuleProperty: {"value1":"location_type","value2":"ldap","description":""} jansModuleProperty: {"value1":"usage_type","value2":"interactive","description":""} jansRevision: 1 -jansScr::%(person_authentication_usercertexternalauthenticator)s +jansScr::%(person_authentication_user_cert_external_authenticator_usercertexternalauthenticator)s jansScrTyp: person_authentication objectClass: top objectClass: jansCustomScr @@ -102,7 +102,7 @@ jansLevel: 40 jansModuleProperty: {"value1":"usage_type","value2":"interactive","description":""} jansModuleProperty: {"value1":"location_type","value2":"ldap","description":""} jansRevision: 1 -jansScr::%(person_authentication_yubicloudexternalauthenticator)s +jansScr::%(person_authentication_yubicloud_external_authenticator_yubicloudexternalauthenticator)s jansScrTyp: person_authentication objectClass: top objectClass: jansCustomScr @@ -234,7 +234,7 @@ jansLevel: 20 jansModuleProperty: {"value1":"location_type","value2":"ldap","description":""} jansModuleProperty: {"value1":"usage_type","value2":"interactive","description":""} jansRevision: 1 -jansScr::%(person_authentication_basiclockaccountexternalauthenticator)s +jansScr::%(person_authentication_basic_lock_account_external_authenticator_basiclockaccountexternalauthenticator)s jansScrTyp: person_authentication objectClass: top objectClass: jansCustomScr @@ -255,7 +255,7 @@ jansLevel: 40 jansModuleProperty: {"value1":"location_type","value2":"ldap","description":""} jansModuleProperty: {"value1":"usage_type","value2":"interactive","description":""} jansRevision: 1 -jansScr::%(person_authentication_otpexternalauthenticator)s +jansScr::%(person_authentication_otp_external_authenticator_otpexternalauthenticator)s jansScrTyp: person_authentication objectClass: top objectClass: jansCustomScr @@ -311,7 +311,7 @@ jansLevel: 60 jansModuleProperty: {"value1":"location_type","value2":"ldap","description":""} jansModuleProperty: {"value1":"usage_type","value2":"interactive","description":""} jansRevision: 1 -jansScr::%(person_authentication_supergluuexternalauthenticator)s +jansScr::%(person_authentication_super_gluu_external_authenticator_supergluuexternalauthenticator)s jansScrTyp: person_authentication objectClass: top objectClass: jansCustomScr @@ -326,7 +326,7 @@ jansLevel: 10 jansModuleProperty: {"value1":"usage_type","value2":"interactive","description":""} jansModuleProperty: {"value1":"location_type","value2":"ldap","description":""} jansRevision: 1 -jansScr::%(person_authentication_basicexternalauthenticator)s +jansScr::%(person_authentication_basic_external_authenticator_basicexternalauthenticator)s jansScrTyp: person_authentication objectClass: top objectClass: jansCustomScr @@ -377,7 +377,7 @@ jansLevel: 50 jansModuleProperty: {"value1":"usage_type","value2":"interactive","description":""} jansModuleProperty: {"value1":"location_type","value2":"ldap","description":""} jansRevision: 1 -jansScr::%(person_authentication_twilio2fa)s +jansScr::%(person_authentication_twilio_2fa_twilio2fa)s jansScrTyp: person_authentication objectClass: top objectClass: jansCustomScr @@ -398,7 +398,7 @@ jansLevel: 45 jansModuleProperty: {"value1":"usage_type","value2":"interactive","description":""} jansModuleProperty: {"value1":"location_type","value2":"ldap","description":""} jansRevision: 1 -jansScr::%(person_authentication_smpp2fa)s +jansScr::%(person_authentication_smpp_2fa_smpp2fa)s jansScrTyp: person_authentication objectClass: top objectClass: jansCustomScr @@ -544,7 +544,7 @@ jansModuleProperty: {"value1":"usage_type","value2":"interactive","description": jansModuleProperty: {"value1":"location_type","value2":"ldap","description": ""} jansProgLng: python jansRevision: 1 -jansScr::%(person_authentication_agamabridge)s +jansScr::%(person_authentication_agama_bridge_agamabridge)s jansScrTyp: person_authentication dn: inum=B270-381E,ou=scripts,o=jans @@ -559,7 +559,7 @@ jansLevel: 10 jansModuleProperty: {"value1":"SCRIPT_FUNCTION","value2":"ldap","description":""} jansProgLng: python jansRevision: 1 -jansScr::%(person_authentication_other_forgot_password_forgot_password)s +jansScr::%(person_authentication_forgot_password_forgot_password)s jansScrTyp: person_authentication dn: inum=CACD-5902,ou=scripts,o=jans