CAS 5.3.0-RC4 - Attribute release not working with MFA gauth groovy type bypass

657 views
Skip to first unread message

Jonathan Barrett

unread,
Jun 21, 2018, 4:29:06 PM6/21/18
to CAS Community
Hello all,

I'm doing testing for upgrading to CAS 5.3.0-RC4 and having problems releasing attributes if I'm using a Groovy script to handle MFA bypass for google authenticator. Note that bypass releases attributes fine if I just use DEFAULT bypass type. I've tried both the /serviceValidate and /samlValidate endpoints. Attribute release also works properly when no bypass happens.

Relevant application.properties config for MFA:
cas.authn.mfa.globalFailureMode=OPEN

cas.authn.mfa.gauth.issuer=TEST
cas.authn.mfa.gauth.label=TEST

cas.authn.mfa.gauth.windowSize=3
cas.authn.mfa.gauth.codeDigits=6
cas.authn.mfa.gauth.timeStepSize=30
cas.authn.mfa.gauth.rank=0
#cas.authn.mfa.gauth.trustedDeviceEnabled=false -- When I have this uncommented I always get errors on startup, does anyone else have this problem?

cas.authn.mfa.gauth.cleaner.schedule.enabled=true
cas.authn.mfa.gauth.cleaner.schedule.startDelay=20000
cas.authn.mfa.gauth.cleaner.schedule.repeatInterval=60000

cas.authn.mfa.gauth.crypto.enabled=false -- I also can't get the tokens to work in 5.3.0-RC4 when encryption is enabled, does anyone else have this problem?

cas.authn.mfa.gauth.bypass.type=GROOVY
#Values for GROOVY
cas.authn.mfa.gauth.bypass.groovy.location=file:/usr/tomcat/mfaGroovyTrigger.groovy
#Values for DEFAULT
#cas.authn.mfa.gauth.bypass.principalAttributeName=mfa-user
#cas.authn.mfa.gauth.bypass.principalAttributeValue=false


mfaGroovyTrigger.groovy:
import java.util.*

def boolean run(final Object... args) {
    def authentication = args[0]
    def principal = args[1]
    def service = args[2]
    def provider = args[3]
    def logger = args[4]
    def httpRequest = args[5]

    logger.info("Evaluating principal attributes ${principal.attributes}")
    def isMfa = principal.attributes['mfa-user']
    if (isMfa != null && isMfa.contains("true")) {
        logger.info("User has MFA registration, do not bypass")
        return true
    }
    if (service.name == "mfareg") {
        if(isMfa != null && isMfa.contains("false")) {
           logger.info("User is going to registration page for the first time, do not bypass")
           return true
        }
    }
    logger.info("User has no MFA registration, bypass")
    return false
}

Condensed log of authentication success but release failure (Note: TGT exists at this time):
2018-06-21 10:49:38,226 INFO [org.apereo.inspektr.audit.support.Slf4jLoggingAuditTrailManager] - <Audit trail record BEGIN
=============================================================
WHO: audit:unknown
WHAT: [result=Service Access Granted,service=<REMOVED>, attributes={<REMOVED>}),requiredAttributes={}]
ACTION: SERVICE_ACCESS_ENFORCEMENT_TRIGGERED
APPLICATION: CAS
WHEN: Thu Jun 21 10:49:38 CDT 2018
CLIENT IP ADDRESS: 
SERVER IP ADDRESS: 
=============================================================

>
2018-06-21 10:49:38,229 DEBUG [org.apereo.cas.authentication.AbstractMultifactorAuthenticationProvider] - <Using global multi-factor failure mode for [AbstractRegisteredService(serviceId<REMOVED>, name=ssomanager, theme=null, informationUrl=null, privacyUrl=null, responseType=null, id=3, description=null, expirationPolicy=DefaultRegisteredServiceExpirationPolicy(deleteWhenExpired=false, notifyWhenDeleted=false, expirationDate=null), proxyPolicy=org.apereo.cas.services.RefuseRegisteredServiceProxyPolicy@1, evaluationOrder=2, usernameAttributeProvider=org.apereo.cas.services.DefaultRegisteredServiceUsernameProvider@87297e2, logoutType=BACK_CHANNEL, requiredHandlers=[], attributeReleasePolicy=ReturnAllAttributeReleasePolicy(super=AbstractRegisteredServiceAttributeReleasePolicy(attributeFilter=null, principalAttributesRepository=DefaultPrincipalAttributesRepository(), consentPolicy=DefaultRegisteredServiceConsentPolicy(enabled=true, excludedAttributes=null, includeOnlyAttributes=null), authorizedToReleaseCredentialPassword=false, authorizedToReleaseProxyGrantingTicket=false, excludeDefaultAttributes=false, authorizedToReleaseAuthenticationAttributes=true, principalIdAttribute=null)), multifactorPolicy=DefaultRegisteredServiceMultifactorPolicy(multifactorAuthenticationProviders=[mfa-gauth], failureMode=NOT_SET, principalAttributeNameTrigger=null, principalAttributeValueToMatch=null, bypassEnabled=false), logo=null, logoutUrl=null, accessStrategy=DefaultRegisteredServiceAccessStrategy(order=0, enabled=true, ssoEnabled=true, unauthorizedRedirectUrl=null, delegatedAuthenticationPolicy=DefaultRegisteredServiceDelegatedAuthenticationPolicy(allowedProviders=[]), requireAllAttributes=true, requiredAttributes={}, rejectedAttributes={}, caseInsensitive=false), publicKey=null, properties={}, contacts=[])] defined as [OPEN]>
2018-06-21 10:49:38,230 DEBUG [org.apereo.cas.authentication.AbstractMultifactorAuthenticationProvider] - <Evaluating multifactor authentication policy for service [AbstractRegisteredService(serviceId=<REMOVED>, name=ssomanager, theme=null, informationUrl=null, privacyUrl=null, responseType=null, id=3, description=null, expirationPolicy=DefaultRegisteredServiceExpirationPolicy(deleteWhenExpired=false, notifyWhenDeleted=false, expirationDate=null), proxyPolicy=org.apereo.cas.services.RefuseRegisteredServiceProxyPolicy@1, evaluationOrder=2, usernameAttributeProvider=org.apereo.cas.services.DefaultRegisteredServiceUsernameProvider@87297e2, logoutType=BACK_CHANNEL, requiredHandlers=[], attributeReleasePolicy=ReturnAllAttributeReleasePolicy(super=AbstractRegisteredServiceAttributeReleasePolicy(attributeFilter=null, principalAttributesRepository=DefaultPrincipalAttributesRepository(), consentPolicy=DefaultRegisteredServiceConsentPolicy(enabled=true, excludedAttributes=null, includeOnlyAttributes=null), authorizedToReleaseCredentialPassword=false, authorizedToReleaseProxyGrantingTicket=false, excludeDefaultAttributes=false, authorizedToReleaseAuthenticationAttributes=true, principalIdAttribute=null)), multifactorPolicy=DefaultRegisteredServiceMultifactorPolicy(multifactorAuthenticationProviders=[mfa-gauth], failureMode=NOT_SET, principalAttributeNameTrigger=null, principalAttributeValueToMatch=null, bypassEnabled=false), logo=null, logoutUrl=null, accessStrategy=DefaultRegisteredServiceAccessStrategy(order=0, enabled=true, ssoEnabled=true, unauthorizedRedirectUrl=null, delegatedAuthenticationPolicy=DefaultRegisteredServiceDelegatedAuthenticationPolicy(allowedProviders=[]), requireAllAttributes=true, requiredAttributes={}, rejectedAttributes={}, caseInsensitive=false), publicKey=null, properties={}, contacts=[])}>
2018-06-21 10:49:38,231 INFO [org.apereo.inspektr.audit.support.Slf4jLoggingAuditTrailManager] - <Audit trail record BEGIN
=============================================================
WHO: audit:unknown
WHAT: [event=mfa-gauth,timestamp=Thu Jun 21 10:49:38 CDT 2018,source=RegisteredServiceMultifactorAuthenticationPolicyEventResolver]
ACTION: AUTHENTICATION_EVENT_TRIGGERED
APPLICATION: CAS
WHEN: Thu Jun 21 10:49:38 CDT 2018
CLIENT IP ADDRESS: 
SERVER IP ADDRESS: 
=============================================================

>
2018-06-21 10:49:38,232 DEBUG [org.apereo.cas.authentication.GroovyMultifactorAuthenticationProviderBypass] - <Evaluating multifactor authentication bypass properties for principal [<REMOVED>], service [AbstractRegisteredService(serviceId=<REMOVED>, name=ssomanager, theme=null, informationUrl=null, privacyUrl=null, responseType=null, id=3, description=null, expirationPolicy=DefaultRegisteredServiceExpirationPolicy(deleteWhenExpired=false, notifyWhenDeleted=false, expirationDate=null), proxyPolicy=org.apereo.cas.services.RefuseRegisteredServiceProxyPolicy@1, evaluationOrder=2, usernameAttributeProvider=org.apereo.cas.services.DefaultRegisteredServiceUsernameProvider@87297e2, logoutType=BACK_CHANNEL, requiredHandlers=[], attributeReleasePolicy=ReturnAllAttributeReleasePolicy(super=AbstractRegisteredServiceAttributeReleasePolicy(attributeFilter=null, principalAttributesRepository=DefaultPrincipalAttributesRepository(), consentPolicy=DefaultRegisteredServiceConsentPolicy(enabled=true, excludedAttributes=null, includeOnlyAttributes=null), authorizedToReleaseCredentialPassword=false, authorizedToReleaseProxyGrantingTicket=false, excludeDefaultAttributes=false, authorizedToReleaseAuthenticationAttributes=true, principalIdAttribute=null)), multifactorPolicy=DefaultRegisteredServiceMultifactorPolicy(multifactorAuthenticationProviders=[mfa-gauth], failureMode=NOT_SET, principalAttributeNameTrigger=null, principalAttributeValueToMatch=null, bypassEnabled=false), logo=null, logoutUrl=null, accessStrategy=DefaultRegisteredServiceAccessStrategy(order=0, enabled=true, ssoEnabled=true, unauthorizedRedirectUrl=null, delegatedAuthenticationPolicy=DefaultRegisteredServiceDelegatedAuthenticationPolicy(allowedProviders=[]), requireAllAttributes=true, requiredAttributes={}, rejectedAttributes={}, caseInsensitive=false), publicKey=null, properties={}, contacts=[])] and provider [AbstractMultifactorAuthenticationProvider(bypassEvaluator=org.apereo.cas.authentication.GroovyMultifactorAuthenticationProviderBypass@7ecbf96e, globalFailureMode=OPEN, id=mfa-gauth, order=0)] via Groovy script [URL [file:/usr/tomcat/mfaGroovyTrigger.groovy]]>
2018-06-21 10:49:38,316 INFO [org.apereo.cas.authentication.GroovyMultifactorAuthenticationProviderBypass] - <Evaluating principal attributes [<REMOVED>]>
2018-06-21 10:49:38,316 INFO [org.apereo.cas.authentication.GroovyMultifactorAuthenticationProviderBypass] - <User has no MFA registration, bypass>
2018-06-21 10:49:38,317 DEBUG [org.apereo.cas.authentication.AbstractMultifactorAuthenticationProvider] - <Request cannot be supported by provider [mfa-gauth] as it's configured for bypass>

<snip, includes authentication event triggered and service access enforcement triggered all the way through attribute resolution and service ticket validation, can add if requested>

2018-06-21 10:49:38,419 DEBUG [org.apereo.cas.AbstractCentralAuthenticationService] - <Publishing [CasServiceTicketValidatedEvent(assertion=ImmutableAssertion(primaryAuthentication=org.apereo.cas.authentication.DefaultAuthentication@601a1344, chainedAuthentications=[org.apereo.cas.authentication.DefaultAuthentication@601a1344], fromNewLogin=false, service=AbstractWebApplicationService(id=<REMOVED>, originalUrl=<REMOVED>, artifactId=null, principal=<REMOVED>, source=service, loggedOutAlready=false, format=XML, attributes={})), serviceTicket=ST-2-oFgH0sXrkimWxBBXDn9-0XP6QFw<REMOVED>)]>
2018-06-21 10:49:38,419 DEBUG [org.apereo.cas.ticket.support.MultiTimeUseOrTimeoutExpirationPolicy] - <Ticket usage count [1] is greater than or equal to [1]. Ticket has expired>
2018-06-21 10:49:38,425 DEBUG [org.apereo.cas.ticket.DefaultTicketCatalog] - <Locating ticket definition for ticket [ST-2-oFgH0sXrkimWxBBXDn9-0XP6QFw<REMOVED>]>
2018-06-21 10:49:38,427 INFO [org.apereo.inspektr.audit.support.Slf4jLoggingAuditTrailManager] - <Audit trail record BEGIN
=============================================================
WHO: <REMOVED>
WHAT: ST-2-oFgH0sXrkimWxBBXDn9-0XP6QFw<REMOVED>
ACTION: SERVICE_TICKET_VALIDATED
APPLICATION: CAS
WHEN: Thu Jun 21 10:49:38 CDT 2018
CLIENT IP ADDRESS: 
SERVER IP ADDRESS: 
=============================================================

>
2018-06-21 10:49:38,427 DEBUG [org.apereo.cas.authentication.PseudoPlatformTransactionManager] - <Initiating transaction commit>
2018-06-21 10:49:38,428 DEBUG [org.apereo.cas.validation.AbstractCasProtocolValidationSpecification] - <Is validation specification set to enforce [renew] protocol behavior? [no]. Is assertion issued from a new login? [no]>
2018-06-21 10:49:38,428 DEBUG [org.apereo.cas.validation.Cas20WithoutProxyingValidationSpecification] - <Number of chained authentications in the assertion [1]>
2018-06-21 10:49:38,429 DEBUG [org.apereo.cas.validation.AbstractCasProtocolValidationSpecification] - <Validation specification is satisfied by the produced assertion>
2018-06-21 10:49:38,429 DEBUG [org.apereo.cas.web.AbstractServiceValidateController] - <Locating the primary authentication associated with this service request [AbstractWebApplicationService(id=<REMOVED>, originalUrl=<REMOVED>, artifactId=null, principal=<REMOVED>, source=service, loggedOutAlready=false, format=XML, attributes={})]>
2018-06-21 10:49:38,432 DEBUG [org.apereo.cas.util.CollectionUtils] - <Converting null obj to empty collection>
2018-06-21 10:49:38,432 DEBUG [org.apereo.cas.authentication.DefaultMultifactorAuthenticationContextValidator] - <Attempting to match requested authentication context [mfa-gauth] against [[]]>
2018-06-21 10:49:38,433 DEBUG [org.apereo.cas.util.CollectionUtils] - <Converting null obj to empty collection>
2018-06-21 10:49:38,433 DEBUG [org.apereo.cas.authentication.DefaultMultifactorAuthenticationContextValidator] - <No authentication context could be determined based on authentication attribute [authnContextClass]>
2018-06-21 10:49:38,433 WARN [org.apereo.cas.authentication.DefaultMultifactorAuthenticationContextValidator] - <No satisfied multifactor authentication providers are recorded in the current authentication context.>
2018-06-21 10:49:38,436 DEBUG [org.apereo.cas.support.saml.authentication.principal.SamlServiceFactory] - <Request Body: [<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><SOAP-ENV:Body><samlp:Request xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol"  MajorVersion="1" MinorVersion="1" RequestID="_00cd501c336a70e6fb627e7aec7a1475" IssueInstant="2018-06-21T15:49:38Z"><samlp:AssertionArtifact>ST-2-oFgH0sXrkimWxBBXDn9-0XP6QFw<REMOVED></samlp:AssertionArtifact></samlp:Request></SOAP-ENV:Body></SOAP-ENV:Envelope>]
"Extracted ArtifactId: [ST-2-oFgH0sXrkimWxBBXDn9-0XP6QFw<REMOVED>]. Extracted Request Id: [_00cd501c336a70e6fb627e7aec7a1475]>
2018-06-21 10:49:38,437 DEBUG [org.apereo.cas.support.saml.web.view.AbstractSaml10ResponseView] - <Using [<REMOVED>] as the recipient of the SAML response for [AbstractWebApplicationService(id=<REMOVED>, originalUrl=<REMOVED>, artifactId=ST-2-oFgH0sXrkimWxBBXDn9-0XP6QFw<REMOVED>, principal=null, source=TARGET, loggedOutAlready=false, format=XML, attributes={})]>
2018-06-21 10:49:38,437 DEBUG [org.apereo.cas.support.saml.web.view.AbstractSaml10ResponseView] - <Created SAML response for service [<REMOVED>]>
2018-06-21 10:49:38,438 DEBUG [org.apereo.cas.support.saml.web.view.AbstractSaml10ResponseView] - <Starting to encode SAML response for service [<REMOVED>]>
2018-06-21 10:49:38,438 DEBUG [org.apereo.cas.support.saml.SamlUtils] - <********************************************************************************>
2018-06-21 10:49:38,441 DEBUG [org.apereo.cas.support.saml.SamlUtils] - <Logging [org.opensaml.saml.saml1.core.impl.ResponseImpl]

<?xml version="1.0" encoding="UTF-8"?><saml1p:Response xmlns:saml1p="urn:oasis:names:tc:SAML:1.0:protocol" InResponseTo="_00cd501c336a70e6fb627e7aec7a1475" IssueInstant="2018-06-21T15:49:33.437Z" MajorVersion="1" MinorVersion="1" ResponseID="_cd9263aae63971ab3fc3987ec1fb90a5">
    <saml1p:Status>
        <saml1p:StatusCode Value="saml1p:RequestDenied"/>
        <saml1p:StatusMessage>The validation request for ['ST-2-oFgH0sXrkimWxBBXDn9-0XP6QFw<REMOVED>'] cannot be satisfied. The request is either unrecognized or unfulfilled.</saml1p:StatusMessage>
    </saml1p:Status>
</saml1p:Response>


>
2018-06-21 10:49:38,442 DEBUG [org.apereo.cas.support.saml.SamlUtils] - <********************************************************************************>

It appears the false my groovy script returns is not making it all the way through the flow to the final validation for attribute release, or the "skip" procedure is returning as a failure instead of a success on bypass for the groovy code.

I can also provide a full log of a successful release using DEFAULT if needed, but here's how the final service ticket validation+transaction looks:
2018-06-21 10:54:45,308 INFO [org.apereo.inspektr.audit.support.Slf4jLoggingAuditTrailManager] - <Audit trail record BEGIN
=============================================================
WHO: 
WHAT: ST-1-VsiLwhJo8TqIkXyZQ3y12-35ahs<REMOVED>
ACTION: SERVICE_TICKET_VALIDATED
APPLICATION: CAS
WHEN: Thu Jun 21 10:54:45 CDT 2018
CLIENT IP ADDRESS: 
SERVER IP ADDRESS: 
=============================================================

>
2018-06-21 10:54:45,309 DEBUG [org.apereo.cas.authentication.PseudoPlatformTransactionManager] - <Initiating transaction commit>
2018-06-21 10:54:45,316 DEBUG [org.apereo.cas.validation.AbstractCasProtocolValidationSpecification] - <Is validation specification set to enforce [renew] protocol behavior? [no]. Is assertion issued from a new login? [yes]>
2018-06-21 10:54:45,317 DEBUG [org.apereo.cas.validation.Cas20WithoutProxyingValidationSpecification] - <Number of chained authentications in the assertion [1]>
2018-06-21 10:54:45,317 DEBUG [org.apereo.cas.validation.AbstractCasProtocolValidationSpecification] - <Validation specification is satisfied by the produced assertion>
2018-06-21 10:54:45,318 DEBUG [org.apereo.cas.web.AbstractServiceValidateController] - <Locating the primary authentication associated with this service request [AbstractWebApplicationService(id=<REMOVED>, originalUrl=<REMOVED>, artifactId=null, principal=<REMOVED>, source=service, loggedOutAlready=false, format=XML, attributes={})]>
2018-06-21 10:54:45,320 DEBUG [org.apereo.cas.util.CollectionUtils] - <Converting null obj to empty collection>
2018-06-21 10:54:45,320 DEBUG [org.apereo.cas.authentication.DefaultMultifactorAuthenticationContextValidator] - <Attempting to match requested authentication context [mfa-gauth] against [[]]>
2018-06-21 10:54:45,321 DEBUG [org.apereo.cas.authentication.DefaultMultifactorAuthenticationContextValidator] - <Found multifactor authentication bypass attributes for provider [mfa-gauth]>
2018-06-21 10:54:45,322 DEBUG [org.apereo.cas.authentication.DefaultMultifactorAuthenticationContextValidator] - <Requested authentication context [mfa-gauth] is satisfied given mfa was bypassed for the authentication attempt>
2018-06-21 10:54:45,322 DEBUG [org.apereo.cas.web.AbstractServiceValidateController] - <No service credentials specified, and/or the proxy handler [org.apereo.cas.ticket.proxy.support.Cas20ProxyHandler@3d07cc9a] cannot handle credentials>
2018-06-21 10:54:45,322 DEBUG [org.apereo.cas.web.AbstractServiceValidateController] - <Successfully validated service ticket [ST-1-VsiLwhJo8TqIkXyZQ3y12-35ahs<REMOVED>] for service [<REMOVED>]>

According to the documentation "Multifactor authentication bypass may be determined using a Groovy script of your own design. The outcome of the script, if true indicates that multifactor authentication for the requested provider should proceed. Otherwise false indicates that multifactor authentication for this provider should be skipped and bypassed." Is the skipping on false causing the issue? I tried digging through the code to try to see if I could pinpoint a potential issue but couldn't find anything conclusive.

I'm not sure if I missed configuration somewhere, working as designed, or if this is a bug. Any assistance is appreciated. First time here, hope this was informative enough to save everyone time!

Thanks,

-Jonathan Barrett

Jonathan Barrett

unread,
Jul 2, 2018, 3:06:05 PM7/2/18
to CAS Community
All,

I was able to resolve the issue by rethinking my program flow and instead rewrite the groovy file to run off of the cas.authn.mfa.groovyScript property so it controls the trigger of MFA instead of bypassing activated MFA. Better to not trigger MFA at all instead of try to bypass in my case. Plus, this gave me the ability to do more preprocessing to push people around to multiple MFA providers as needed. Be aware that service.id at the trigger level is the URL instead of the service registry name/ID. Hope this helps someone.

-Jonathan

Dirk Tepe

unread,
Aug 22, 2018, 4:08:50 PM8/22/18
to CAS Community
Can you provide some details regarding your configuration to get cas.authn.mfa.groovyScript working? I'm currently using a groovy script for MFA bypass successfully but now have need to use one for triggering as well. However, the triggering script example wraps the run method in a class and I've not been successful in getting it executed. CAS complains if I have the path to the file incorrect, so I know it's at least identifying that the file exists, I just can't figure out how to get it executed.

Thanks,

-dirk

Jonathan Barrett

unread,
Sep 11, 2018, 11:10:00 AM9/11/18
to CAS Community
Dirk,

Sorry for the huge delay, here's all my config related to the cas.authn.mfa.gauth piece (sans our JPA config, since it doesn't sound like you need it):

cas.authn.mfa.globalFailureMode=OPEN
#cas.authn.mfa.globalPrincipalAttributeNameTriggers=mfa-user
#cas.authn.mfa.globalProviderId=mfa-gauth
cas.authn.mfa.groovyScript=file:/usr/tomcat/mfaAuthTrigger.groovy

cas.authn.mfa.gauth.issuer=TEST
cas.authn.mfa.gauth.label=TEST

cas.authn.mfa.gauth.windowSize=3
cas.authn.mfa.gauth.codeDigits=6
cas.authn.mfa.gauth.timeStepSize=30
cas.authn.mfa.gauth.rank=0
#cas.authn.mfa.gauth.trustedDeviceEnabled=false -- I still can't get this to work

cas.authn.mfa.gauth.cleaner.schedule.enabled=true
cas.authn.mfa.gauth.cleaner.schedule.startDelay=20000
cas.authn.mfa.gauth.cleaner.schedule.repeatInterval=60000

Be sure the file is on a location that the tomcat user can read from. I just put it in tomcat root for simplicity's sake.

I hope this helps if you're still having problems.

Thanks,

-Jonathan

Tepe, Dirk

unread,
Sep 11, 2018, 2:09:23 PM9/11/18
to cas-...@apereo.org
Thanks. I was able to get it working eventually. Part of the problem is that while CAS supports groovy scripts in multiple places, there are different conventions for how the script must be structured. I was eventually able to sort it all out.

Thanks very much for taking the time to get back with me, though.

-dirk

--
- Website: https://apereo.github.io/cas
- Gitter Chatroom: https://gitter.im/apereo/cas
- List Guidelines: https://goo.gl/1VRrw7
- Contributions: https://goo.gl/mh7qDG
---
You received this message because you are subscribed to the Google Groups "CAS Community" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cas-user+u...@apereo.org.
To view this discussion on the web visit https://groups.google.com/a/apereo.org/d/msgid/cas-user/ceaf9267-c5c6-4597-b029-36487945f801%40apereo.org.
Reply all
Reply to author
Forward
0 new messages