CAS 6.6.6
Is it possible to use Simple MFA as part of initial authentication and then flow to Surrogate selection?
(1) Have full deployment working with MFA, and Surrogate functioning, but not for the same authentication instance. If MFA triggered during authentication then surrogate selection is bypassed. Would like to be able to have ability for Simple MFA then proceed to surrogacy if authenticating user logins in with +username. If this is even possible.
(2) With simple MFA, using couchDb for storage, what is the correct setting for MFA expiration? For instance require MFA every 30 days. All settings seem to leave couchDb expiration defaulting to 100 years in the future. Guessing un-documented parameter, not implemented, or a glitch. Worked around this with a nightly batch process to update the expirationDate relative to recordDate for all newly generated cache entries in couchDb. As an FYI, if expirationDate is greater than systemdate, couchDb entry will automatically be removed either during CAS scheduled cleanup, or if record is read during MFA.
Spent extensive time ironing out details and testing with MFA and Surrogate, but could not solve (1). Would be good to know (2) for reference, or at least make note of it.
# from service file
"matchingStrategy": {
"@class": "org.apereo.cas.services.FullRegexRegisteredServiceMatchingStrategy",
"caseInsensitive": true
},
"authenticationPolicy" : {
"@class" : "org.apereo.cas.services.DefaultRegisteredServiceAuthenticationPolicy",
"requiredAuthenticationHandlers" : ["java.util.TreeSet", [ "NetworkUser" ]],
"criteria": {
"@class": "org.apereo.cas.services.AllowedAuthenticationHandlersRegisteredServiceAuthenticationPolicyCriteria"
}
},
"usernameAttributeProvider" : {
"@class" : "org.apereo.cas.services.PrincipalAttributeRegisteredServiceUsernameProvider",
"usernameAttribute" : "username",
"canonicalizationMode" : "NONE"
},
"attributeReleasePolicy" : {
"principalAttributesRepository" : {
"@class" : "org.apereo.cas.authentication.principal.DefaultPrincipalAttributesRepository",
"ignoreResolvedAttributes": false,
"attributeRepositoryIds": ["java.util.HashSet", [ "usersimpersonated" ]],
"mergingStrategy" : "REPLACE"
},
"@class" : "org.apereo.cas.services.ReturnAllowedAttributeReleasePolicy",
"allowedAttributes" : [ "java.util.ArrayList", [ "email", "username", "name_first", "name_last", "mfa_mode", "phone", "impersonate"] ]
},
cas.authn.authentication-attribute-release.enabled=true
# These attributes are released to determine whether to use mfa or impersonation
cas.authn.attribute-repository.core.default-attributes-to-release=mfa_mode,username,impersonate,email,phone
# Setting the expiration time to 0 disables caching these attributes in memory,
# so they will be retrieved each time
cas.authn.attribute-repository.core.expiration-time=0
# use cascade so that the attributes from initial queries can be used as the
# query for the next repository
cas.authn.attribute-repository.core.aggregation=CASCADE
# this has to be set to REPLACE, otherwise the process fails between the simple name/pass
# login and the MFA step
cas.authn.attribute-repository.core.merger=REPLACE
## MFA settings
cas.authn.mfa.web-authn.core.enabled=true
cas.authn.mfa.trusted.device-fingerprint.cookie.max-age=-1
### this setting does NOT seem to have any effect on MFA expiration ###
cas.authn.mfa.web-authn.core.expire-devices=30
cas.authn.mfa.web-authn.core.expire-devices-time-unit=DAYS
cas.authn.mfa.trusted.cleaner.schedule.enabled-on-host=.*
cas.authn.mfa.trusted.cleaner.schedule.enabled=true
cas.authn.mfa.trusted.cleaner.schedule.repeat-interval=PT2M
cas.authn.mfa.trusted.cleaner.schedule.start-delay=PT15S
cas.authn.mfa.web-authn.crypto.encryption.key=<hidden>
cas.authn.mfa.web-authn.crypto.signing.key=<hidden>
# use couchDb to cache MFA
cas.authn.mfa.trusted.couch-db.caching=false
cas.authn.mfa.trusted.couch-db.db-name=<db name>
cas.authn.mfa.trusted.couch-db.username=<hidden>
cas.authn.mfa.trusted.couch-db.password=<hidden>
cas.authn.mfa.trusted.couch-db.url=<hidden>
# leave as false, auto-create for MFA 6.6 is broken
# (HAVE TO LOAD THE MFA DB DESIGN MANUALLY)
cas.authn.mfa.trusted.couch-db.create-if-not-exists=false
cas.authn.mfa.core.provider-selection-enabled=false
cas.authn.mfa.simple.id=mfa-simple
cas.authn.mfa.simple.name=mfa-simple
cas.authn.mfa.simple.mail.from=<hidden>
cas.authn.mfa.simple.mail.text=/<path to>/mfa_email.gtemplate
cas.authn.mfa.simple.mail.subject= Your login code
cas.authn.mfa.simple.mail.attribute-name=email
cas.authn.mfa.simple.mail.validate-addresses=true
cas.authn.mfa.simple.sms.attribute-name=phone
cas.authn.mfa.simple.sms.from=<hidden>
cas.authn.mfa.simple.sms.text=/<path to>/mfa_sms.gtemplate
# due to a strange limitation in sending just the digits of the token
# directly through Twilio ==> communicating to Twilio with a groovy script
# that can first strip out the extra characters
cas.sms-provider.groovy.location=file:/<path to>/send_sms.groovy
## time the generated token is valid for (set to 10 minutes)
cas.authn.mfa.simple.token.core.time-to-kill-in-seconds=600
cas.authn.mfa.simple.token.core.token-length=6
cas.authn.mfa.simple.trusted-device-enabled=true
cas.authn.mfa.simple.order=1
cas.authn.mfa.simple.failure-mode=OPEN
# Trigger MFA based on outcome of Groovy script (instead of using a global setting)
cas.authn.mfa.groovy-script.location=file:/etc/cas/casint/config/mfa_trigger.groovy
# Trusted MFA Devices
cas.authn.mfa.trusted.crypto.encryption.key=<hidden>
cas.authn.mfa.trusted.crypto.signing.key=<hidden>
cas.authn.mfa.trusted.device-fingerprint.cookie.crypto.encryption.key=<hidden>
cas.authn.mfa.trusted.device-fingerprint.cookie.crypto.signing.key=<hidden>
cas.authn.mfa.trusted.core.device-registration-enabled=true
cas.authn.mfa.trusted.core.auto-assign-device-name=true
cas.authn.mfa.trusted.core.authentication-context-attribute=isFromTrustedMultifactorAuthentication
# MFA Fingerprint Settings
# To control what is saved in the database during MFA
cas.authn.mfa.trusted.device-fingerprint.component-separator=@
cas.authn.mfa.trusted.device-fingerprint.cookie.enabled=true
cas.authn.mfa.trusted.device-fingerprint.cookie.order=1
cas.authn.mfa.trusted.device-fingerprint.client-ip.enabled=true
cas.authn.mfa.trusted.device-fingerprint.client-ip.order=2
cas.authn.mfa.trusted.device-fingerprint.user-agent.enabled=false
cas.authn.mfa.trusted.device-fingerprint.user-agent.order=3
cas.authn.mfa.trusted.device-fingerprint.cookie.comment=CAS Cookie
cas.authn.mfa.trusted.device-fingerprint.cookie.name=CASMFACookie
cas.authn.mfa.trusted.device-fingerprint.cookie.secure=false
cas.authn.mfa.trusted.device-fingerprint.cookie.http-only=false
# Surrogate attribute repository settings
##
## configure an attribute repository used by impersonation (in this case we are using the
## impersonatee's username to retrieve their info from this attribute repository)
##
## the <users who can be impersonated view> is every possible user who can be impersonated
##
cas.authn.attribute-repository.jdbc[0].id=usersimpersonated
cas.authn.attribute-repository.jdbc[0].driver-class=oracle.jdbc.OracleDriver
cas.authn.attribute-repository.jdbc[0].dialect=org.hibernate.dialect.Oracle12cDialect
cas.authn.attribute-repository.jdbc[0].url=<hidden>
## NOTE: the {0} in the following WHERE clause is replaced with username from the jdbc[2].username=username
## authentication setting ==> this is also 100% dependent upon the final username being resolved before using this
## ==> even though there are person directory settings for principal attribute, those
## are 100% (ignored?) / over-ridden by what is returned as the principal attribute from
## prior authentication actions
##
cas.authn.attribute-repository.jdbc[0].sql=SELECT * FROM <users who can be impersonated view> WHERE {0}
cas.authn.attribute-repository.jdbc[0].read-only=true
cas.authn.attribute-repository.jdbc[0].require-all-attributes=false
cas.authn.attribute-repository.jdbc[0].single-row=true
cas.authn.attribute-repository.jdbc[0].state=ACTIVE
cas.authn.attribute-repository.jdbc[0].attributes.name_first=name_first
cas.authn.attribute-repository.jdbc[0].attributes.name_last=name_last
cas.authn.attribute-repository.jdbc[0].attributes.mfa_mode=mfa_mode
cas.authn.attribute-repository.jdbc[0].attributes.username=username
cas.authn.attribute-repository.jdbc[0].attributes.impersonate=impersonate
cas.authn.attribute-repository.jdbc[0].attributes.email=email
cas.authn.attribute-repository.jdbc[0].attributes.phone=phone
cas.authn.attribute-repository.jdbc[0].attributes.lowerusername=lowerusername
# a lowercase version of the username is necessary in order for
# the surrogate match/drop down to work correctly, while at the
# same time allowing the username attribute to remain case sensitive
#
# lowerusername is NOT included in the released attributes
cas.authn.attribute-repository.jdbc[0].username=lowerusername
cas.authn.attribute-repository.jdbc[0].password=<hidden>
cas.authn.attribute-repository.jdbc[0].user=<hidden>
cas.authn.attribute-repository.jdbc[0].case-insensitive-query-attributes=username->NONE
cas.authn.attribute-repository.jdbc[0].default-schema=<hidden>
cas.authn.attribute-repository.jdbc[0].autocommit=false
cas.authn.attribute-repository.jdbc[0].batch-size=1
cas.authn.attribute-repository.jdbc[0].ddl-auto=none
cas.authn.attribute-repository.jdbc[0].fail-fast-timeout=1
cas.authn.attribute-repository.jdbc[0].fetch-size=2000
cas.authn.attribute-repository.jdbc[0].health-query=select 1 from dual
cas.authn.attribute-repository.jdbc[0].idle-timeout=PT10M
cas.authn.attribute-repository.jdbc[0].isolate-internal-queries=false
cas.authn.attribute-repository.jdbc[0].isolation-level-name=ISOLATION_READ_COMMITTED
cas.authn.attribute-repository.jdbc[0].leak-threshold=10
cas.authn.attribute-repository.jdbc[0].order=1
cas.authn.attribute-repository.jdbc[0].pool.keep-alive-time=0
cas.authn.attribute-repository.jdbc[0].pool.max-size=18
cas.authn.attribute-repository.jdbc[0].pool.max-wait=PT20S
cas.authn.attribute-repository.jdbc[0].pool.maximum-lifetime=PT10M
cas.authn.attribute-repository.jdbc[0].pool.min-size=6
cas.authn.attribute-repository.jdbc[0].pool.suspension=false
cas.authn.attribute-repository.jdbc[0].pool.timeout-millis=1000
cas.authn.attribute-repository.jdbc[0].propagation-behavior-name=PROPAGATION_REQUIRED
cas.person-directory.active-attribute-repository-ids=usersimpersonated
cas.person-directory.attribute-resolution-enabled=true
cas.person-directory.principal-resolution-conflict-strategy=last
cas.person-directory.principal-resolution-failure-fatal=false
cas.person-directory.principal-transformation.case-conversion=NONE
cas.person-directory.return-null=true
cas.person-directory.use-existing-principal-id=false
##
## configure impersonation
##
cas.authn.jaas[0].realm=CAS
cas.authn.surrogate.separator=+
# Timeout in seconds to kill the surrogate session and consider tickets expired.
# currently set to 8 hours
cas.authn.surrogate.tgt.time-to-kill-in-seconds=28800
cas.authn.surrogate.principal.active-attribute-repository-ids=usersimpersonated
cas.authn.surrogate.principal.attribute-resolution-enabled=true
cas.authn.surrogate.principal.principal-attribute=username
cas.authn.surrogate.principal.principal-resolution-conflict-strategy=last
cas.authn.surrogate.principal.principal-resolution-failure-fatal=false
cas.authn.surrogate.principal.principal-transformation.case-conversion=NONE
cas.authn.surrogate.principal.return-null=true
cas.authn.surrogate.principal.use-existing-principal-id=false
cas.authn.surrogate.jdbc.driver-class=oracle.jdbc.OracleDriver
cas.authn.surrogate.jdbc.dialect=org.hibernate.dialect.Oracle12cDialect
cas.authn.surrogate.jdbc.url=<hidden>
cas.authn.surrogate.jdbc.user=<hidden>
cas.authn.surrogate.jdbc.password=<hidden>
cas.authn.surrogate.jdbc.default-schema=<hidden>
cas.authn.surrogate.jdbc.ddl-auto=none
cas.authn.surrogate.jdbc.leak-threshold=10000
# NOTE: both of the following queries are wrapping the username with LOWER
# ==> this is necessary for the impersonation dropdown selector to sort
# and work correctly with short cut keys ==> this DOES NOT impact the
# username release attribute (which needs to be case sensitive)
# NOTE: the following queries may not match the documentation...
# the 6.x documentation appears incorrect in regards to these queries
# deterimine whether authenicated user can impersonate another user
cas.authn.surrogate.jdbc.surrogate-search-query=SELECT COUNT(*) FROM <users per impersonator view> WHERE impersonator = ? AND LOWER(username) = ?
# list of qualified accounts that can be impersonated per the "authenticated" impersonating user
cas.authn.surrogate.jdbc.surrogate-account-query=SELECT LOWER(username) AS surrogateAccount FROM <users per impersonator view> WHERE impersonator = ?