How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona...

67
How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University of Arizona - UITS

Transcript of How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona...

Page 1: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

How The University of Arizona Addressed SSO for Office 365

Gary Windham

Senior Enterprise Systems Architect The University of Arizona - UITS

[ 2 ]

CONTENTS

How The University of Arizona Addressed SSO for Office 365

bull All Aboard Office 365 ndash Mind the Gap

bull Shibboleth ndash the Sugrureg of SSO

bull Staying Agile ndash Containerization and Cloud Deployment

bull Demo

[ 3 ]

By WillMcC - Own work CC BY-SA 30 httpscommonswikimediaorgwindexphpcurid=4379199

[ 4 ]

Wersquore moving all staff and faculty to Office 365

bull project kickoff was in October 2016

bull motivations

ndash part of larger strategy to migrate the bulk of central IT services to the cloud

ndash avoid having to make further capital expenditures to accommodate growth

bull migrating from on-prem Exchange 2013

ndash ~ 33K mailboxes

ndash ~ 60TB storage

[ 5 ]

Federated SSO with AD will solve all our problems

[ 6 ]

Assumptions and realizations

bull initial assumption was that we would use ADFS with our on-prem Active

Directory for federated SSO

bull as requirements were fleshed-out we realized we had needs not easily

addressed by federated SSO with ADhellip

bull needed to authenticate different types of accounts residing in disjoint OUs

ndash normal user accounts (UA NetIDs)

ndash service accounts

ndash domain admin accounts

[ 7 ]

Assumptions and realizations (cont)

bull MFA authentication with w Duo Security + varying behavior depending on account type

ndash NetIDs use custom-built 2FA registration portal (NetID+)

ndash service accounts and domain admin accounts arent NetIDs

bull required separate Duo application integrations to handle enrollment via the Duo Web SDK

bull app passwords

ndash we have a significant number of legacy clients

bull cant use Microsofts modern authentication (ADAL)

bull can only use ECP for federated authentication ndash ECP endpoint not supported by AD

ndash we didnt want to completely sacrifice MFA for these clients

ndash plan provide application-specific password functionality

ndash couldnrsquot use Azure app passwords unless we also adopted Azure MFA

bull campus already has significant investment in Duo

[ 8 ]

The long tail of email clients

bull Office365 supports Modern Authentication

ndash ADAL (Azure AD Authentication Libraries)

ndash Facilitates web SSO authentication in native applications

ndash Makes MFA feasible with native email clients

bull recent Outlook clients support Modern Authentication

ndash enabled by default in Office 2016

ndash available but not enabled by default in Office 2013

bull very heterogeneous email client landscape

ndash older versions of Outlook

ndash Apple Mail

ndash Thunderbird

ndash various 3rd-party mobile POPIMAP clients PINE mutt any conceivable thing faculty might install

[ 9 ]

Shibboleth mdash The Sugru reg of SSO

[ 10 ]

Shibboleth mdash The Sugru reg of SSO

[ 11 ]

Shibboleth mdash The Sugru reg of SSO

[ 12 ]

Shibboleth mdash The Sugru reg of SSO

[ 13 ]

Shibboleth mdash The Sugru reg of SSO

[ 14 ]

Shibboleth mdash The Sugru reg of SSO

[ 15 ]

Shibboleth IdP Environment

bull Shibboleth IdP v331 running in Docker containers

ndash Centos 7

ndash Oracle JDK 8

ndash Jetty 9

bull Authentication Components

ndash MultiFactorAuthnConfiguration

ndash DuoAuthnConfiguration

ndash JAASAuthnConfiguration

[ 16 ]

Challenge 1 ndash Authenticate via LDAP BIND against 3 disjoint AD OUs

bull need to attempt authentications against 3 different OUs in Active Directory

bull OUs house separate user populations

ndash normal users (NetIDs)

ndash service accounts

ndash delegated domain admins

bull need to keep track of which OU user was authenticated against in order to use

different MFA configurations in subsequent step

[ 17 ]

JAAS to the rescue

bull JAAS = Java Authentication and Authorization Service

bull (from the Shibboleth Wiki) JAAS is a desktop authentication mechanism in

Java that has been commonly misappropriated as a server-side technology

bull PAM-like can have multiple configurations that are tried in succession until

one succeeds

[ 18 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

[ 19 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct base DNs

(could be distinct servers)

[ 20 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct LDAP connection pools

[ 21 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

[ 22 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

[ 23 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

Build app password service (agrave la Google or Azure MFA) which stores

application-specific passwords in a separate store and requires same level of

authentication as logging-in to O365

[ 24 ]

Configuring ECP in Shibboleth

bull what is ECP

ndash Enhanced Client or Proxy

ndash client that is not a browser

ndash The ECP profile is an adaptation of the SAML profile used for Browser SSO with the

parts that were designed around the limitations of a browser removed

bull configuring ECP for password-based authN is pretty straightforward and is

described on Shibboleth wiki [1]

bull how do we know to access app password store for authentication credentials

when ECP binding is used (will get to this in next challenge)

[ 25 ]

App Password Store

bull requirements are simple

ndash user can have unlimited number of app passwords

ndash passwords are stored in hashed format (using PBKDF2)

ndash store createdOn lastUsed and simple text description (eg name of app that will be using password)

bull where to store passwords

ndash Shib IdP will have multiple nodes (for HA) so we need a shared data source

ndash dedicated relational DB seems like overkill

ndash ended up settling on AWS DynamoDB

bull will be running Shib IdP hosts in AWS

bull minimal costmaintenanceeffort

bull not really worried about backing up data (beyond replication for HA purposes)

bull app password management application

ndash serverless NodeJS application also running in AWS (using Lambda and API Gateway)

ndash use Passportjs for SAML authentication against our IdP

ndash use AWS Javascript SDK to interface with DynamoDB

[ 26 ]

Interfacing the password store w Shib

bull DynamoDB has a low-level HTTP-based API plus numerous higher-level API

bindings (eg Java Python Javascript etc)

bull since we were already using JAAS we developed a simple JAAS module

based on Jan Oppolzerrsquos jaas-rdbms-hashed [2]

bull not much effort

ndash had to adapt the Utils class (which performs password hashing) to use

PBKDF2WithHmacSHA256 instead of SHA256

ndash created a DynamoDB client factory that uses synchronized HashMap to allow for

multiple JAAS DynamoDB login configs each with their own client connection pool

ndash implement login() method of javaxsecurityauthspiLoginModule to

interface with DynamoDB

[ 27 ]

Add new JAAS configuration

bull create a jar for our JAAS module amp drop it in Shib IdP distributionrsquos webappsWEB-INFlib folder

bull add following to confauthnjaasconfig

ECPPasswordAuth eduarizonauitssiajaasdynamodbDynamoDBLogin requiredregion=us-west-2table=o365-app-pwpartitionKey=netidsortKey=hashedPwpwSalt=random stringcacheId=ddb

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 2: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 2 ]

CONTENTS

How The University of Arizona Addressed SSO for Office 365

bull All Aboard Office 365 ndash Mind the Gap

bull Shibboleth ndash the Sugrureg of SSO

bull Staying Agile ndash Containerization and Cloud Deployment

bull Demo

[ 3 ]

By WillMcC - Own work CC BY-SA 30 httpscommonswikimediaorgwindexphpcurid=4379199

[ 4 ]

Wersquore moving all staff and faculty to Office 365

bull project kickoff was in October 2016

bull motivations

ndash part of larger strategy to migrate the bulk of central IT services to the cloud

ndash avoid having to make further capital expenditures to accommodate growth

bull migrating from on-prem Exchange 2013

ndash ~ 33K mailboxes

ndash ~ 60TB storage

[ 5 ]

Federated SSO with AD will solve all our problems

[ 6 ]

Assumptions and realizations

bull initial assumption was that we would use ADFS with our on-prem Active

Directory for federated SSO

bull as requirements were fleshed-out we realized we had needs not easily

addressed by federated SSO with ADhellip

bull needed to authenticate different types of accounts residing in disjoint OUs

ndash normal user accounts (UA NetIDs)

ndash service accounts

ndash domain admin accounts

[ 7 ]

Assumptions and realizations (cont)

bull MFA authentication with w Duo Security + varying behavior depending on account type

ndash NetIDs use custom-built 2FA registration portal (NetID+)

ndash service accounts and domain admin accounts arent NetIDs

bull required separate Duo application integrations to handle enrollment via the Duo Web SDK

bull app passwords

ndash we have a significant number of legacy clients

bull cant use Microsofts modern authentication (ADAL)

bull can only use ECP for federated authentication ndash ECP endpoint not supported by AD

ndash we didnt want to completely sacrifice MFA for these clients

ndash plan provide application-specific password functionality

ndash couldnrsquot use Azure app passwords unless we also adopted Azure MFA

bull campus already has significant investment in Duo

[ 8 ]

The long tail of email clients

bull Office365 supports Modern Authentication

ndash ADAL (Azure AD Authentication Libraries)

ndash Facilitates web SSO authentication in native applications

ndash Makes MFA feasible with native email clients

bull recent Outlook clients support Modern Authentication

ndash enabled by default in Office 2016

ndash available but not enabled by default in Office 2013

bull very heterogeneous email client landscape

ndash older versions of Outlook

ndash Apple Mail

ndash Thunderbird

ndash various 3rd-party mobile POPIMAP clients PINE mutt any conceivable thing faculty might install

[ 9 ]

Shibboleth mdash The Sugru reg of SSO

[ 10 ]

Shibboleth mdash The Sugru reg of SSO

[ 11 ]

Shibboleth mdash The Sugru reg of SSO

[ 12 ]

Shibboleth mdash The Sugru reg of SSO

[ 13 ]

Shibboleth mdash The Sugru reg of SSO

[ 14 ]

Shibboleth mdash The Sugru reg of SSO

[ 15 ]

Shibboleth IdP Environment

bull Shibboleth IdP v331 running in Docker containers

ndash Centos 7

ndash Oracle JDK 8

ndash Jetty 9

bull Authentication Components

ndash MultiFactorAuthnConfiguration

ndash DuoAuthnConfiguration

ndash JAASAuthnConfiguration

[ 16 ]

Challenge 1 ndash Authenticate via LDAP BIND against 3 disjoint AD OUs

bull need to attempt authentications against 3 different OUs in Active Directory

bull OUs house separate user populations

ndash normal users (NetIDs)

ndash service accounts

ndash delegated domain admins

bull need to keep track of which OU user was authenticated against in order to use

different MFA configurations in subsequent step

[ 17 ]

JAAS to the rescue

bull JAAS = Java Authentication and Authorization Service

bull (from the Shibboleth Wiki) JAAS is a desktop authentication mechanism in

Java that has been commonly misappropriated as a server-side technology

bull PAM-like can have multiple configurations that are tried in succession until

one succeeds

[ 18 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

[ 19 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct base DNs

(could be distinct servers)

[ 20 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct LDAP connection pools

[ 21 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

[ 22 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

[ 23 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

Build app password service (agrave la Google or Azure MFA) which stores

application-specific passwords in a separate store and requires same level of

authentication as logging-in to O365

[ 24 ]

Configuring ECP in Shibboleth

bull what is ECP

ndash Enhanced Client or Proxy

ndash client that is not a browser

ndash The ECP profile is an adaptation of the SAML profile used for Browser SSO with the

parts that were designed around the limitations of a browser removed

bull configuring ECP for password-based authN is pretty straightforward and is

described on Shibboleth wiki [1]

bull how do we know to access app password store for authentication credentials

when ECP binding is used (will get to this in next challenge)

[ 25 ]

App Password Store

bull requirements are simple

ndash user can have unlimited number of app passwords

ndash passwords are stored in hashed format (using PBKDF2)

ndash store createdOn lastUsed and simple text description (eg name of app that will be using password)

bull where to store passwords

ndash Shib IdP will have multiple nodes (for HA) so we need a shared data source

ndash dedicated relational DB seems like overkill

ndash ended up settling on AWS DynamoDB

bull will be running Shib IdP hosts in AWS

bull minimal costmaintenanceeffort

bull not really worried about backing up data (beyond replication for HA purposes)

bull app password management application

ndash serverless NodeJS application also running in AWS (using Lambda and API Gateway)

ndash use Passportjs for SAML authentication against our IdP

ndash use AWS Javascript SDK to interface with DynamoDB

[ 26 ]

Interfacing the password store w Shib

bull DynamoDB has a low-level HTTP-based API plus numerous higher-level API

bindings (eg Java Python Javascript etc)

bull since we were already using JAAS we developed a simple JAAS module

based on Jan Oppolzerrsquos jaas-rdbms-hashed [2]

bull not much effort

ndash had to adapt the Utils class (which performs password hashing) to use

PBKDF2WithHmacSHA256 instead of SHA256

ndash created a DynamoDB client factory that uses synchronized HashMap to allow for

multiple JAAS DynamoDB login configs each with their own client connection pool

ndash implement login() method of javaxsecurityauthspiLoginModule to

interface with DynamoDB

[ 27 ]

Add new JAAS configuration

bull create a jar for our JAAS module amp drop it in Shib IdP distributionrsquos webappsWEB-INFlib folder

bull add following to confauthnjaasconfig

ECPPasswordAuth eduarizonauitssiajaasdynamodbDynamoDBLogin requiredregion=us-west-2table=o365-app-pwpartitionKey=netidsortKey=hashedPwpwSalt=random stringcacheId=ddb

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 3: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 3 ]

By WillMcC - Own work CC BY-SA 30 httpscommonswikimediaorgwindexphpcurid=4379199

[ 4 ]

Wersquore moving all staff and faculty to Office 365

bull project kickoff was in October 2016

bull motivations

ndash part of larger strategy to migrate the bulk of central IT services to the cloud

ndash avoid having to make further capital expenditures to accommodate growth

bull migrating from on-prem Exchange 2013

ndash ~ 33K mailboxes

ndash ~ 60TB storage

[ 5 ]

Federated SSO with AD will solve all our problems

[ 6 ]

Assumptions and realizations

bull initial assumption was that we would use ADFS with our on-prem Active

Directory for federated SSO

bull as requirements were fleshed-out we realized we had needs not easily

addressed by federated SSO with ADhellip

bull needed to authenticate different types of accounts residing in disjoint OUs

ndash normal user accounts (UA NetIDs)

ndash service accounts

ndash domain admin accounts

[ 7 ]

Assumptions and realizations (cont)

bull MFA authentication with w Duo Security + varying behavior depending on account type

ndash NetIDs use custom-built 2FA registration portal (NetID+)

ndash service accounts and domain admin accounts arent NetIDs

bull required separate Duo application integrations to handle enrollment via the Duo Web SDK

bull app passwords

ndash we have a significant number of legacy clients

bull cant use Microsofts modern authentication (ADAL)

bull can only use ECP for federated authentication ndash ECP endpoint not supported by AD

ndash we didnt want to completely sacrifice MFA for these clients

ndash plan provide application-specific password functionality

ndash couldnrsquot use Azure app passwords unless we also adopted Azure MFA

bull campus already has significant investment in Duo

[ 8 ]

The long tail of email clients

bull Office365 supports Modern Authentication

ndash ADAL (Azure AD Authentication Libraries)

ndash Facilitates web SSO authentication in native applications

ndash Makes MFA feasible with native email clients

bull recent Outlook clients support Modern Authentication

ndash enabled by default in Office 2016

ndash available but not enabled by default in Office 2013

bull very heterogeneous email client landscape

ndash older versions of Outlook

ndash Apple Mail

ndash Thunderbird

ndash various 3rd-party mobile POPIMAP clients PINE mutt any conceivable thing faculty might install

[ 9 ]

Shibboleth mdash The Sugru reg of SSO

[ 10 ]

Shibboleth mdash The Sugru reg of SSO

[ 11 ]

Shibboleth mdash The Sugru reg of SSO

[ 12 ]

Shibboleth mdash The Sugru reg of SSO

[ 13 ]

Shibboleth mdash The Sugru reg of SSO

[ 14 ]

Shibboleth mdash The Sugru reg of SSO

[ 15 ]

Shibboleth IdP Environment

bull Shibboleth IdP v331 running in Docker containers

ndash Centos 7

ndash Oracle JDK 8

ndash Jetty 9

bull Authentication Components

ndash MultiFactorAuthnConfiguration

ndash DuoAuthnConfiguration

ndash JAASAuthnConfiguration

[ 16 ]

Challenge 1 ndash Authenticate via LDAP BIND against 3 disjoint AD OUs

bull need to attempt authentications against 3 different OUs in Active Directory

bull OUs house separate user populations

ndash normal users (NetIDs)

ndash service accounts

ndash delegated domain admins

bull need to keep track of which OU user was authenticated against in order to use

different MFA configurations in subsequent step

[ 17 ]

JAAS to the rescue

bull JAAS = Java Authentication and Authorization Service

bull (from the Shibboleth Wiki) JAAS is a desktop authentication mechanism in

Java that has been commonly misappropriated as a server-side technology

bull PAM-like can have multiple configurations that are tried in succession until

one succeeds

[ 18 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

[ 19 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct base DNs

(could be distinct servers)

[ 20 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct LDAP connection pools

[ 21 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

[ 22 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

[ 23 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

Build app password service (agrave la Google or Azure MFA) which stores

application-specific passwords in a separate store and requires same level of

authentication as logging-in to O365

[ 24 ]

Configuring ECP in Shibboleth

bull what is ECP

ndash Enhanced Client or Proxy

ndash client that is not a browser

ndash The ECP profile is an adaptation of the SAML profile used for Browser SSO with the

parts that were designed around the limitations of a browser removed

bull configuring ECP for password-based authN is pretty straightforward and is

described on Shibboleth wiki [1]

bull how do we know to access app password store for authentication credentials

when ECP binding is used (will get to this in next challenge)

[ 25 ]

App Password Store

bull requirements are simple

ndash user can have unlimited number of app passwords

ndash passwords are stored in hashed format (using PBKDF2)

ndash store createdOn lastUsed and simple text description (eg name of app that will be using password)

bull where to store passwords

ndash Shib IdP will have multiple nodes (for HA) so we need a shared data source

ndash dedicated relational DB seems like overkill

ndash ended up settling on AWS DynamoDB

bull will be running Shib IdP hosts in AWS

bull minimal costmaintenanceeffort

bull not really worried about backing up data (beyond replication for HA purposes)

bull app password management application

ndash serverless NodeJS application also running in AWS (using Lambda and API Gateway)

ndash use Passportjs for SAML authentication against our IdP

ndash use AWS Javascript SDK to interface with DynamoDB

[ 26 ]

Interfacing the password store w Shib

bull DynamoDB has a low-level HTTP-based API plus numerous higher-level API

bindings (eg Java Python Javascript etc)

bull since we were already using JAAS we developed a simple JAAS module

based on Jan Oppolzerrsquos jaas-rdbms-hashed [2]

bull not much effort

ndash had to adapt the Utils class (which performs password hashing) to use

PBKDF2WithHmacSHA256 instead of SHA256

ndash created a DynamoDB client factory that uses synchronized HashMap to allow for

multiple JAAS DynamoDB login configs each with their own client connection pool

ndash implement login() method of javaxsecurityauthspiLoginModule to

interface with DynamoDB

[ 27 ]

Add new JAAS configuration

bull create a jar for our JAAS module amp drop it in Shib IdP distributionrsquos webappsWEB-INFlib folder

bull add following to confauthnjaasconfig

ECPPasswordAuth eduarizonauitssiajaasdynamodbDynamoDBLogin requiredregion=us-west-2table=o365-app-pwpartitionKey=netidsortKey=hashedPwpwSalt=random stringcacheId=ddb

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 4: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 4 ]

Wersquore moving all staff and faculty to Office 365

bull project kickoff was in October 2016

bull motivations

ndash part of larger strategy to migrate the bulk of central IT services to the cloud

ndash avoid having to make further capital expenditures to accommodate growth

bull migrating from on-prem Exchange 2013

ndash ~ 33K mailboxes

ndash ~ 60TB storage

[ 5 ]

Federated SSO with AD will solve all our problems

[ 6 ]

Assumptions and realizations

bull initial assumption was that we would use ADFS with our on-prem Active

Directory for federated SSO

bull as requirements were fleshed-out we realized we had needs not easily

addressed by federated SSO with ADhellip

bull needed to authenticate different types of accounts residing in disjoint OUs

ndash normal user accounts (UA NetIDs)

ndash service accounts

ndash domain admin accounts

[ 7 ]

Assumptions and realizations (cont)

bull MFA authentication with w Duo Security + varying behavior depending on account type

ndash NetIDs use custom-built 2FA registration portal (NetID+)

ndash service accounts and domain admin accounts arent NetIDs

bull required separate Duo application integrations to handle enrollment via the Duo Web SDK

bull app passwords

ndash we have a significant number of legacy clients

bull cant use Microsofts modern authentication (ADAL)

bull can only use ECP for federated authentication ndash ECP endpoint not supported by AD

ndash we didnt want to completely sacrifice MFA for these clients

ndash plan provide application-specific password functionality

ndash couldnrsquot use Azure app passwords unless we also adopted Azure MFA

bull campus already has significant investment in Duo

[ 8 ]

The long tail of email clients

bull Office365 supports Modern Authentication

ndash ADAL (Azure AD Authentication Libraries)

ndash Facilitates web SSO authentication in native applications

ndash Makes MFA feasible with native email clients

bull recent Outlook clients support Modern Authentication

ndash enabled by default in Office 2016

ndash available but not enabled by default in Office 2013

bull very heterogeneous email client landscape

ndash older versions of Outlook

ndash Apple Mail

ndash Thunderbird

ndash various 3rd-party mobile POPIMAP clients PINE mutt any conceivable thing faculty might install

[ 9 ]

Shibboleth mdash The Sugru reg of SSO

[ 10 ]

Shibboleth mdash The Sugru reg of SSO

[ 11 ]

Shibboleth mdash The Sugru reg of SSO

[ 12 ]

Shibboleth mdash The Sugru reg of SSO

[ 13 ]

Shibboleth mdash The Sugru reg of SSO

[ 14 ]

Shibboleth mdash The Sugru reg of SSO

[ 15 ]

Shibboleth IdP Environment

bull Shibboleth IdP v331 running in Docker containers

ndash Centos 7

ndash Oracle JDK 8

ndash Jetty 9

bull Authentication Components

ndash MultiFactorAuthnConfiguration

ndash DuoAuthnConfiguration

ndash JAASAuthnConfiguration

[ 16 ]

Challenge 1 ndash Authenticate via LDAP BIND against 3 disjoint AD OUs

bull need to attempt authentications against 3 different OUs in Active Directory

bull OUs house separate user populations

ndash normal users (NetIDs)

ndash service accounts

ndash delegated domain admins

bull need to keep track of which OU user was authenticated against in order to use

different MFA configurations in subsequent step

[ 17 ]

JAAS to the rescue

bull JAAS = Java Authentication and Authorization Service

bull (from the Shibboleth Wiki) JAAS is a desktop authentication mechanism in

Java that has been commonly misappropriated as a server-side technology

bull PAM-like can have multiple configurations that are tried in succession until

one succeeds

[ 18 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

[ 19 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct base DNs

(could be distinct servers)

[ 20 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct LDAP connection pools

[ 21 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

[ 22 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

[ 23 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

Build app password service (agrave la Google or Azure MFA) which stores

application-specific passwords in a separate store and requires same level of

authentication as logging-in to O365

[ 24 ]

Configuring ECP in Shibboleth

bull what is ECP

ndash Enhanced Client or Proxy

ndash client that is not a browser

ndash The ECP profile is an adaptation of the SAML profile used for Browser SSO with the

parts that were designed around the limitations of a browser removed

bull configuring ECP for password-based authN is pretty straightforward and is

described on Shibboleth wiki [1]

bull how do we know to access app password store for authentication credentials

when ECP binding is used (will get to this in next challenge)

[ 25 ]

App Password Store

bull requirements are simple

ndash user can have unlimited number of app passwords

ndash passwords are stored in hashed format (using PBKDF2)

ndash store createdOn lastUsed and simple text description (eg name of app that will be using password)

bull where to store passwords

ndash Shib IdP will have multiple nodes (for HA) so we need a shared data source

ndash dedicated relational DB seems like overkill

ndash ended up settling on AWS DynamoDB

bull will be running Shib IdP hosts in AWS

bull minimal costmaintenanceeffort

bull not really worried about backing up data (beyond replication for HA purposes)

bull app password management application

ndash serverless NodeJS application also running in AWS (using Lambda and API Gateway)

ndash use Passportjs for SAML authentication against our IdP

ndash use AWS Javascript SDK to interface with DynamoDB

[ 26 ]

Interfacing the password store w Shib

bull DynamoDB has a low-level HTTP-based API plus numerous higher-level API

bindings (eg Java Python Javascript etc)

bull since we were already using JAAS we developed a simple JAAS module

based on Jan Oppolzerrsquos jaas-rdbms-hashed [2]

bull not much effort

ndash had to adapt the Utils class (which performs password hashing) to use

PBKDF2WithHmacSHA256 instead of SHA256

ndash created a DynamoDB client factory that uses synchronized HashMap to allow for

multiple JAAS DynamoDB login configs each with their own client connection pool

ndash implement login() method of javaxsecurityauthspiLoginModule to

interface with DynamoDB

[ 27 ]

Add new JAAS configuration

bull create a jar for our JAAS module amp drop it in Shib IdP distributionrsquos webappsWEB-INFlib folder

bull add following to confauthnjaasconfig

ECPPasswordAuth eduarizonauitssiajaasdynamodbDynamoDBLogin requiredregion=us-west-2table=o365-app-pwpartitionKey=netidsortKey=hashedPwpwSalt=random stringcacheId=ddb

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 5: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 5 ]

Federated SSO with AD will solve all our problems

[ 6 ]

Assumptions and realizations

bull initial assumption was that we would use ADFS with our on-prem Active

Directory for federated SSO

bull as requirements were fleshed-out we realized we had needs not easily

addressed by federated SSO with ADhellip

bull needed to authenticate different types of accounts residing in disjoint OUs

ndash normal user accounts (UA NetIDs)

ndash service accounts

ndash domain admin accounts

[ 7 ]

Assumptions and realizations (cont)

bull MFA authentication with w Duo Security + varying behavior depending on account type

ndash NetIDs use custom-built 2FA registration portal (NetID+)

ndash service accounts and domain admin accounts arent NetIDs

bull required separate Duo application integrations to handle enrollment via the Duo Web SDK

bull app passwords

ndash we have a significant number of legacy clients

bull cant use Microsofts modern authentication (ADAL)

bull can only use ECP for federated authentication ndash ECP endpoint not supported by AD

ndash we didnt want to completely sacrifice MFA for these clients

ndash plan provide application-specific password functionality

ndash couldnrsquot use Azure app passwords unless we also adopted Azure MFA

bull campus already has significant investment in Duo

[ 8 ]

The long tail of email clients

bull Office365 supports Modern Authentication

ndash ADAL (Azure AD Authentication Libraries)

ndash Facilitates web SSO authentication in native applications

ndash Makes MFA feasible with native email clients

bull recent Outlook clients support Modern Authentication

ndash enabled by default in Office 2016

ndash available but not enabled by default in Office 2013

bull very heterogeneous email client landscape

ndash older versions of Outlook

ndash Apple Mail

ndash Thunderbird

ndash various 3rd-party mobile POPIMAP clients PINE mutt any conceivable thing faculty might install

[ 9 ]

Shibboleth mdash The Sugru reg of SSO

[ 10 ]

Shibboleth mdash The Sugru reg of SSO

[ 11 ]

Shibboleth mdash The Sugru reg of SSO

[ 12 ]

Shibboleth mdash The Sugru reg of SSO

[ 13 ]

Shibboleth mdash The Sugru reg of SSO

[ 14 ]

Shibboleth mdash The Sugru reg of SSO

[ 15 ]

Shibboleth IdP Environment

bull Shibboleth IdP v331 running in Docker containers

ndash Centos 7

ndash Oracle JDK 8

ndash Jetty 9

bull Authentication Components

ndash MultiFactorAuthnConfiguration

ndash DuoAuthnConfiguration

ndash JAASAuthnConfiguration

[ 16 ]

Challenge 1 ndash Authenticate via LDAP BIND against 3 disjoint AD OUs

bull need to attempt authentications against 3 different OUs in Active Directory

bull OUs house separate user populations

ndash normal users (NetIDs)

ndash service accounts

ndash delegated domain admins

bull need to keep track of which OU user was authenticated against in order to use

different MFA configurations in subsequent step

[ 17 ]

JAAS to the rescue

bull JAAS = Java Authentication and Authorization Service

bull (from the Shibboleth Wiki) JAAS is a desktop authentication mechanism in

Java that has been commonly misappropriated as a server-side technology

bull PAM-like can have multiple configurations that are tried in succession until

one succeeds

[ 18 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

[ 19 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct base DNs

(could be distinct servers)

[ 20 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct LDAP connection pools

[ 21 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

[ 22 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

[ 23 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

Build app password service (agrave la Google or Azure MFA) which stores

application-specific passwords in a separate store and requires same level of

authentication as logging-in to O365

[ 24 ]

Configuring ECP in Shibboleth

bull what is ECP

ndash Enhanced Client or Proxy

ndash client that is not a browser

ndash The ECP profile is an adaptation of the SAML profile used for Browser SSO with the

parts that were designed around the limitations of a browser removed

bull configuring ECP for password-based authN is pretty straightforward and is

described on Shibboleth wiki [1]

bull how do we know to access app password store for authentication credentials

when ECP binding is used (will get to this in next challenge)

[ 25 ]

App Password Store

bull requirements are simple

ndash user can have unlimited number of app passwords

ndash passwords are stored in hashed format (using PBKDF2)

ndash store createdOn lastUsed and simple text description (eg name of app that will be using password)

bull where to store passwords

ndash Shib IdP will have multiple nodes (for HA) so we need a shared data source

ndash dedicated relational DB seems like overkill

ndash ended up settling on AWS DynamoDB

bull will be running Shib IdP hosts in AWS

bull minimal costmaintenanceeffort

bull not really worried about backing up data (beyond replication for HA purposes)

bull app password management application

ndash serverless NodeJS application also running in AWS (using Lambda and API Gateway)

ndash use Passportjs for SAML authentication against our IdP

ndash use AWS Javascript SDK to interface with DynamoDB

[ 26 ]

Interfacing the password store w Shib

bull DynamoDB has a low-level HTTP-based API plus numerous higher-level API

bindings (eg Java Python Javascript etc)

bull since we were already using JAAS we developed a simple JAAS module

based on Jan Oppolzerrsquos jaas-rdbms-hashed [2]

bull not much effort

ndash had to adapt the Utils class (which performs password hashing) to use

PBKDF2WithHmacSHA256 instead of SHA256

ndash created a DynamoDB client factory that uses synchronized HashMap to allow for

multiple JAAS DynamoDB login configs each with their own client connection pool

ndash implement login() method of javaxsecurityauthspiLoginModule to

interface with DynamoDB

[ 27 ]

Add new JAAS configuration

bull create a jar for our JAAS module amp drop it in Shib IdP distributionrsquos webappsWEB-INFlib folder

bull add following to confauthnjaasconfig

ECPPasswordAuth eduarizonauitssiajaasdynamodbDynamoDBLogin requiredregion=us-west-2table=o365-app-pwpartitionKey=netidsortKey=hashedPwpwSalt=random stringcacheId=ddb

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 6: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 6 ]

Assumptions and realizations

bull initial assumption was that we would use ADFS with our on-prem Active

Directory for federated SSO

bull as requirements were fleshed-out we realized we had needs not easily

addressed by federated SSO with ADhellip

bull needed to authenticate different types of accounts residing in disjoint OUs

ndash normal user accounts (UA NetIDs)

ndash service accounts

ndash domain admin accounts

[ 7 ]

Assumptions and realizations (cont)

bull MFA authentication with w Duo Security + varying behavior depending on account type

ndash NetIDs use custom-built 2FA registration portal (NetID+)

ndash service accounts and domain admin accounts arent NetIDs

bull required separate Duo application integrations to handle enrollment via the Duo Web SDK

bull app passwords

ndash we have a significant number of legacy clients

bull cant use Microsofts modern authentication (ADAL)

bull can only use ECP for federated authentication ndash ECP endpoint not supported by AD

ndash we didnt want to completely sacrifice MFA for these clients

ndash plan provide application-specific password functionality

ndash couldnrsquot use Azure app passwords unless we also adopted Azure MFA

bull campus already has significant investment in Duo

[ 8 ]

The long tail of email clients

bull Office365 supports Modern Authentication

ndash ADAL (Azure AD Authentication Libraries)

ndash Facilitates web SSO authentication in native applications

ndash Makes MFA feasible with native email clients

bull recent Outlook clients support Modern Authentication

ndash enabled by default in Office 2016

ndash available but not enabled by default in Office 2013

bull very heterogeneous email client landscape

ndash older versions of Outlook

ndash Apple Mail

ndash Thunderbird

ndash various 3rd-party mobile POPIMAP clients PINE mutt any conceivable thing faculty might install

[ 9 ]

Shibboleth mdash The Sugru reg of SSO

[ 10 ]

Shibboleth mdash The Sugru reg of SSO

[ 11 ]

Shibboleth mdash The Sugru reg of SSO

[ 12 ]

Shibboleth mdash The Sugru reg of SSO

[ 13 ]

Shibboleth mdash The Sugru reg of SSO

[ 14 ]

Shibboleth mdash The Sugru reg of SSO

[ 15 ]

Shibboleth IdP Environment

bull Shibboleth IdP v331 running in Docker containers

ndash Centos 7

ndash Oracle JDK 8

ndash Jetty 9

bull Authentication Components

ndash MultiFactorAuthnConfiguration

ndash DuoAuthnConfiguration

ndash JAASAuthnConfiguration

[ 16 ]

Challenge 1 ndash Authenticate via LDAP BIND against 3 disjoint AD OUs

bull need to attempt authentications against 3 different OUs in Active Directory

bull OUs house separate user populations

ndash normal users (NetIDs)

ndash service accounts

ndash delegated domain admins

bull need to keep track of which OU user was authenticated against in order to use

different MFA configurations in subsequent step

[ 17 ]

JAAS to the rescue

bull JAAS = Java Authentication and Authorization Service

bull (from the Shibboleth Wiki) JAAS is a desktop authentication mechanism in

Java that has been commonly misappropriated as a server-side technology

bull PAM-like can have multiple configurations that are tried in succession until

one succeeds

[ 18 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

[ 19 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct base DNs

(could be distinct servers)

[ 20 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct LDAP connection pools

[ 21 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

[ 22 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

[ 23 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

Build app password service (agrave la Google or Azure MFA) which stores

application-specific passwords in a separate store and requires same level of

authentication as logging-in to O365

[ 24 ]

Configuring ECP in Shibboleth

bull what is ECP

ndash Enhanced Client or Proxy

ndash client that is not a browser

ndash The ECP profile is an adaptation of the SAML profile used for Browser SSO with the

parts that were designed around the limitations of a browser removed

bull configuring ECP for password-based authN is pretty straightforward and is

described on Shibboleth wiki [1]

bull how do we know to access app password store for authentication credentials

when ECP binding is used (will get to this in next challenge)

[ 25 ]

App Password Store

bull requirements are simple

ndash user can have unlimited number of app passwords

ndash passwords are stored in hashed format (using PBKDF2)

ndash store createdOn lastUsed and simple text description (eg name of app that will be using password)

bull where to store passwords

ndash Shib IdP will have multiple nodes (for HA) so we need a shared data source

ndash dedicated relational DB seems like overkill

ndash ended up settling on AWS DynamoDB

bull will be running Shib IdP hosts in AWS

bull minimal costmaintenanceeffort

bull not really worried about backing up data (beyond replication for HA purposes)

bull app password management application

ndash serverless NodeJS application also running in AWS (using Lambda and API Gateway)

ndash use Passportjs for SAML authentication against our IdP

ndash use AWS Javascript SDK to interface with DynamoDB

[ 26 ]

Interfacing the password store w Shib

bull DynamoDB has a low-level HTTP-based API plus numerous higher-level API

bindings (eg Java Python Javascript etc)

bull since we were already using JAAS we developed a simple JAAS module

based on Jan Oppolzerrsquos jaas-rdbms-hashed [2]

bull not much effort

ndash had to adapt the Utils class (which performs password hashing) to use

PBKDF2WithHmacSHA256 instead of SHA256

ndash created a DynamoDB client factory that uses synchronized HashMap to allow for

multiple JAAS DynamoDB login configs each with their own client connection pool

ndash implement login() method of javaxsecurityauthspiLoginModule to

interface with DynamoDB

[ 27 ]

Add new JAAS configuration

bull create a jar for our JAAS module amp drop it in Shib IdP distributionrsquos webappsWEB-INFlib folder

bull add following to confauthnjaasconfig

ECPPasswordAuth eduarizonauitssiajaasdynamodbDynamoDBLogin requiredregion=us-west-2table=o365-app-pwpartitionKey=netidsortKey=hashedPwpwSalt=random stringcacheId=ddb

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 7: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 7 ]

Assumptions and realizations (cont)

bull MFA authentication with w Duo Security + varying behavior depending on account type

ndash NetIDs use custom-built 2FA registration portal (NetID+)

ndash service accounts and domain admin accounts arent NetIDs

bull required separate Duo application integrations to handle enrollment via the Duo Web SDK

bull app passwords

ndash we have a significant number of legacy clients

bull cant use Microsofts modern authentication (ADAL)

bull can only use ECP for federated authentication ndash ECP endpoint not supported by AD

ndash we didnt want to completely sacrifice MFA for these clients

ndash plan provide application-specific password functionality

ndash couldnrsquot use Azure app passwords unless we also adopted Azure MFA

bull campus already has significant investment in Duo

[ 8 ]

The long tail of email clients

bull Office365 supports Modern Authentication

ndash ADAL (Azure AD Authentication Libraries)

ndash Facilitates web SSO authentication in native applications

ndash Makes MFA feasible with native email clients

bull recent Outlook clients support Modern Authentication

ndash enabled by default in Office 2016

ndash available but not enabled by default in Office 2013

bull very heterogeneous email client landscape

ndash older versions of Outlook

ndash Apple Mail

ndash Thunderbird

ndash various 3rd-party mobile POPIMAP clients PINE mutt any conceivable thing faculty might install

[ 9 ]

Shibboleth mdash The Sugru reg of SSO

[ 10 ]

Shibboleth mdash The Sugru reg of SSO

[ 11 ]

Shibboleth mdash The Sugru reg of SSO

[ 12 ]

Shibboleth mdash The Sugru reg of SSO

[ 13 ]

Shibboleth mdash The Sugru reg of SSO

[ 14 ]

Shibboleth mdash The Sugru reg of SSO

[ 15 ]

Shibboleth IdP Environment

bull Shibboleth IdP v331 running in Docker containers

ndash Centos 7

ndash Oracle JDK 8

ndash Jetty 9

bull Authentication Components

ndash MultiFactorAuthnConfiguration

ndash DuoAuthnConfiguration

ndash JAASAuthnConfiguration

[ 16 ]

Challenge 1 ndash Authenticate via LDAP BIND against 3 disjoint AD OUs

bull need to attempt authentications against 3 different OUs in Active Directory

bull OUs house separate user populations

ndash normal users (NetIDs)

ndash service accounts

ndash delegated domain admins

bull need to keep track of which OU user was authenticated against in order to use

different MFA configurations in subsequent step

[ 17 ]

JAAS to the rescue

bull JAAS = Java Authentication and Authorization Service

bull (from the Shibboleth Wiki) JAAS is a desktop authentication mechanism in

Java that has been commonly misappropriated as a server-side technology

bull PAM-like can have multiple configurations that are tried in succession until

one succeeds

[ 18 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

[ 19 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct base DNs

(could be distinct servers)

[ 20 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct LDAP connection pools

[ 21 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

[ 22 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

[ 23 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

Build app password service (agrave la Google or Azure MFA) which stores

application-specific passwords in a separate store and requires same level of

authentication as logging-in to O365

[ 24 ]

Configuring ECP in Shibboleth

bull what is ECP

ndash Enhanced Client or Proxy

ndash client that is not a browser

ndash The ECP profile is an adaptation of the SAML profile used for Browser SSO with the

parts that were designed around the limitations of a browser removed

bull configuring ECP for password-based authN is pretty straightforward and is

described on Shibboleth wiki [1]

bull how do we know to access app password store for authentication credentials

when ECP binding is used (will get to this in next challenge)

[ 25 ]

App Password Store

bull requirements are simple

ndash user can have unlimited number of app passwords

ndash passwords are stored in hashed format (using PBKDF2)

ndash store createdOn lastUsed and simple text description (eg name of app that will be using password)

bull where to store passwords

ndash Shib IdP will have multiple nodes (for HA) so we need a shared data source

ndash dedicated relational DB seems like overkill

ndash ended up settling on AWS DynamoDB

bull will be running Shib IdP hosts in AWS

bull minimal costmaintenanceeffort

bull not really worried about backing up data (beyond replication for HA purposes)

bull app password management application

ndash serverless NodeJS application also running in AWS (using Lambda and API Gateway)

ndash use Passportjs for SAML authentication against our IdP

ndash use AWS Javascript SDK to interface with DynamoDB

[ 26 ]

Interfacing the password store w Shib

bull DynamoDB has a low-level HTTP-based API plus numerous higher-level API

bindings (eg Java Python Javascript etc)

bull since we were already using JAAS we developed a simple JAAS module

based on Jan Oppolzerrsquos jaas-rdbms-hashed [2]

bull not much effort

ndash had to adapt the Utils class (which performs password hashing) to use

PBKDF2WithHmacSHA256 instead of SHA256

ndash created a DynamoDB client factory that uses synchronized HashMap to allow for

multiple JAAS DynamoDB login configs each with their own client connection pool

ndash implement login() method of javaxsecurityauthspiLoginModule to

interface with DynamoDB

[ 27 ]

Add new JAAS configuration

bull create a jar for our JAAS module amp drop it in Shib IdP distributionrsquos webappsWEB-INFlib folder

bull add following to confauthnjaasconfig

ECPPasswordAuth eduarizonauitssiajaasdynamodbDynamoDBLogin requiredregion=us-west-2table=o365-app-pwpartitionKey=netidsortKey=hashedPwpwSalt=random stringcacheId=ddb

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 8: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 8 ]

The long tail of email clients

bull Office365 supports Modern Authentication

ndash ADAL (Azure AD Authentication Libraries)

ndash Facilitates web SSO authentication in native applications

ndash Makes MFA feasible with native email clients

bull recent Outlook clients support Modern Authentication

ndash enabled by default in Office 2016

ndash available but not enabled by default in Office 2013

bull very heterogeneous email client landscape

ndash older versions of Outlook

ndash Apple Mail

ndash Thunderbird

ndash various 3rd-party mobile POPIMAP clients PINE mutt any conceivable thing faculty might install

[ 9 ]

Shibboleth mdash The Sugru reg of SSO

[ 10 ]

Shibboleth mdash The Sugru reg of SSO

[ 11 ]

Shibboleth mdash The Sugru reg of SSO

[ 12 ]

Shibboleth mdash The Sugru reg of SSO

[ 13 ]

Shibboleth mdash The Sugru reg of SSO

[ 14 ]

Shibboleth mdash The Sugru reg of SSO

[ 15 ]

Shibboleth IdP Environment

bull Shibboleth IdP v331 running in Docker containers

ndash Centos 7

ndash Oracle JDK 8

ndash Jetty 9

bull Authentication Components

ndash MultiFactorAuthnConfiguration

ndash DuoAuthnConfiguration

ndash JAASAuthnConfiguration

[ 16 ]

Challenge 1 ndash Authenticate via LDAP BIND against 3 disjoint AD OUs

bull need to attempt authentications against 3 different OUs in Active Directory

bull OUs house separate user populations

ndash normal users (NetIDs)

ndash service accounts

ndash delegated domain admins

bull need to keep track of which OU user was authenticated against in order to use

different MFA configurations in subsequent step

[ 17 ]

JAAS to the rescue

bull JAAS = Java Authentication and Authorization Service

bull (from the Shibboleth Wiki) JAAS is a desktop authentication mechanism in

Java that has been commonly misappropriated as a server-side technology

bull PAM-like can have multiple configurations that are tried in succession until

one succeeds

[ 18 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

[ 19 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct base DNs

(could be distinct servers)

[ 20 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct LDAP connection pools

[ 21 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

[ 22 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

[ 23 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

Build app password service (agrave la Google or Azure MFA) which stores

application-specific passwords in a separate store and requires same level of

authentication as logging-in to O365

[ 24 ]

Configuring ECP in Shibboleth

bull what is ECP

ndash Enhanced Client or Proxy

ndash client that is not a browser

ndash The ECP profile is an adaptation of the SAML profile used for Browser SSO with the

parts that were designed around the limitations of a browser removed

bull configuring ECP for password-based authN is pretty straightforward and is

described on Shibboleth wiki [1]

bull how do we know to access app password store for authentication credentials

when ECP binding is used (will get to this in next challenge)

[ 25 ]

App Password Store

bull requirements are simple

ndash user can have unlimited number of app passwords

ndash passwords are stored in hashed format (using PBKDF2)

ndash store createdOn lastUsed and simple text description (eg name of app that will be using password)

bull where to store passwords

ndash Shib IdP will have multiple nodes (for HA) so we need a shared data source

ndash dedicated relational DB seems like overkill

ndash ended up settling on AWS DynamoDB

bull will be running Shib IdP hosts in AWS

bull minimal costmaintenanceeffort

bull not really worried about backing up data (beyond replication for HA purposes)

bull app password management application

ndash serverless NodeJS application also running in AWS (using Lambda and API Gateway)

ndash use Passportjs for SAML authentication against our IdP

ndash use AWS Javascript SDK to interface with DynamoDB

[ 26 ]

Interfacing the password store w Shib

bull DynamoDB has a low-level HTTP-based API plus numerous higher-level API

bindings (eg Java Python Javascript etc)

bull since we were already using JAAS we developed a simple JAAS module

based on Jan Oppolzerrsquos jaas-rdbms-hashed [2]

bull not much effort

ndash had to adapt the Utils class (which performs password hashing) to use

PBKDF2WithHmacSHA256 instead of SHA256

ndash created a DynamoDB client factory that uses synchronized HashMap to allow for

multiple JAAS DynamoDB login configs each with their own client connection pool

ndash implement login() method of javaxsecurityauthspiLoginModule to

interface with DynamoDB

[ 27 ]

Add new JAAS configuration

bull create a jar for our JAAS module amp drop it in Shib IdP distributionrsquos webappsWEB-INFlib folder

bull add following to confauthnjaasconfig

ECPPasswordAuth eduarizonauitssiajaasdynamodbDynamoDBLogin requiredregion=us-west-2table=o365-app-pwpartitionKey=netidsortKey=hashedPwpwSalt=random stringcacheId=ddb

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 9: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 9 ]

Shibboleth mdash The Sugru reg of SSO

[ 10 ]

Shibboleth mdash The Sugru reg of SSO

[ 11 ]

Shibboleth mdash The Sugru reg of SSO

[ 12 ]

Shibboleth mdash The Sugru reg of SSO

[ 13 ]

Shibboleth mdash The Sugru reg of SSO

[ 14 ]

Shibboleth mdash The Sugru reg of SSO

[ 15 ]

Shibboleth IdP Environment

bull Shibboleth IdP v331 running in Docker containers

ndash Centos 7

ndash Oracle JDK 8

ndash Jetty 9

bull Authentication Components

ndash MultiFactorAuthnConfiguration

ndash DuoAuthnConfiguration

ndash JAASAuthnConfiguration

[ 16 ]

Challenge 1 ndash Authenticate via LDAP BIND against 3 disjoint AD OUs

bull need to attempt authentications against 3 different OUs in Active Directory

bull OUs house separate user populations

ndash normal users (NetIDs)

ndash service accounts

ndash delegated domain admins

bull need to keep track of which OU user was authenticated against in order to use

different MFA configurations in subsequent step

[ 17 ]

JAAS to the rescue

bull JAAS = Java Authentication and Authorization Service

bull (from the Shibboleth Wiki) JAAS is a desktop authentication mechanism in

Java that has been commonly misappropriated as a server-side technology

bull PAM-like can have multiple configurations that are tried in succession until

one succeeds

[ 18 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

[ 19 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct base DNs

(could be distinct servers)

[ 20 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct LDAP connection pools

[ 21 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

[ 22 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

[ 23 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

Build app password service (agrave la Google or Azure MFA) which stores

application-specific passwords in a separate store and requires same level of

authentication as logging-in to O365

[ 24 ]

Configuring ECP in Shibboleth

bull what is ECP

ndash Enhanced Client or Proxy

ndash client that is not a browser

ndash The ECP profile is an adaptation of the SAML profile used for Browser SSO with the

parts that were designed around the limitations of a browser removed

bull configuring ECP for password-based authN is pretty straightforward and is

described on Shibboleth wiki [1]

bull how do we know to access app password store for authentication credentials

when ECP binding is used (will get to this in next challenge)

[ 25 ]

App Password Store

bull requirements are simple

ndash user can have unlimited number of app passwords

ndash passwords are stored in hashed format (using PBKDF2)

ndash store createdOn lastUsed and simple text description (eg name of app that will be using password)

bull where to store passwords

ndash Shib IdP will have multiple nodes (for HA) so we need a shared data source

ndash dedicated relational DB seems like overkill

ndash ended up settling on AWS DynamoDB

bull will be running Shib IdP hosts in AWS

bull minimal costmaintenanceeffort

bull not really worried about backing up data (beyond replication for HA purposes)

bull app password management application

ndash serverless NodeJS application also running in AWS (using Lambda and API Gateway)

ndash use Passportjs for SAML authentication against our IdP

ndash use AWS Javascript SDK to interface with DynamoDB

[ 26 ]

Interfacing the password store w Shib

bull DynamoDB has a low-level HTTP-based API plus numerous higher-level API

bindings (eg Java Python Javascript etc)

bull since we were already using JAAS we developed a simple JAAS module

based on Jan Oppolzerrsquos jaas-rdbms-hashed [2]

bull not much effort

ndash had to adapt the Utils class (which performs password hashing) to use

PBKDF2WithHmacSHA256 instead of SHA256

ndash created a DynamoDB client factory that uses synchronized HashMap to allow for

multiple JAAS DynamoDB login configs each with their own client connection pool

ndash implement login() method of javaxsecurityauthspiLoginModule to

interface with DynamoDB

[ 27 ]

Add new JAAS configuration

bull create a jar for our JAAS module amp drop it in Shib IdP distributionrsquos webappsWEB-INFlib folder

bull add following to confauthnjaasconfig

ECPPasswordAuth eduarizonauitssiajaasdynamodbDynamoDBLogin requiredregion=us-west-2table=o365-app-pwpartitionKey=netidsortKey=hashedPwpwSalt=random stringcacheId=ddb

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 10: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 10 ]

Shibboleth mdash The Sugru reg of SSO

[ 11 ]

Shibboleth mdash The Sugru reg of SSO

[ 12 ]

Shibboleth mdash The Sugru reg of SSO

[ 13 ]

Shibboleth mdash The Sugru reg of SSO

[ 14 ]

Shibboleth mdash The Sugru reg of SSO

[ 15 ]

Shibboleth IdP Environment

bull Shibboleth IdP v331 running in Docker containers

ndash Centos 7

ndash Oracle JDK 8

ndash Jetty 9

bull Authentication Components

ndash MultiFactorAuthnConfiguration

ndash DuoAuthnConfiguration

ndash JAASAuthnConfiguration

[ 16 ]

Challenge 1 ndash Authenticate via LDAP BIND against 3 disjoint AD OUs

bull need to attempt authentications against 3 different OUs in Active Directory

bull OUs house separate user populations

ndash normal users (NetIDs)

ndash service accounts

ndash delegated domain admins

bull need to keep track of which OU user was authenticated against in order to use

different MFA configurations in subsequent step

[ 17 ]

JAAS to the rescue

bull JAAS = Java Authentication and Authorization Service

bull (from the Shibboleth Wiki) JAAS is a desktop authentication mechanism in

Java that has been commonly misappropriated as a server-side technology

bull PAM-like can have multiple configurations that are tried in succession until

one succeeds

[ 18 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

[ 19 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct base DNs

(could be distinct servers)

[ 20 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct LDAP connection pools

[ 21 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

[ 22 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

[ 23 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

Build app password service (agrave la Google or Azure MFA) which stores

application-specific passwords in a separate store and requires same level of

authentication as logging-in to O365

[ 24 ]

Configuring ECP in Shibboleth

bull what is ECP

ndash Enhanced Client or Proxy

ndash client that is not a browser

ndash The ECP profile is an adaptation of the SAML profile used for Browser SSO with the

parts that were designed around the limitations of a browser removed

bull configuring ECP for password-based authN is pretty straightforward and is

described on Shibboleth wiki [1]

bull how do we know to access app password store for authentication credentials

when ECP binding is used (will get to this in next challenge)

[ 25 ]

App Password Store

bull requirements are simple

ndash user can have unlimited number of app passwords

ndash passwords are stored in hashed format (using PBKDF2)

ndash store createdOn lastUsed and simple text description (eg name of app that will be using password)

bull where to store passwords

ndash Shib IdP will have multiple nodes (for HA) so we need a shared data source

ndash dedicated relational DB seems like overkill

ndash ended up settling on AWS DynamoDB

bull will be running Shib IdP hosts in AWS

bull minimal costmaintenanceeffort

bull not really worried about backing up data (beyond replication for HA purposes)

bull app password management application

ndash serverless NodeJS application also running in AWS (using Lambda and API Gateway)

ndash use Passportjs for SAML authentication against our IdP

ndash use AWS Javascript SDK to interface with DynamoDB

[ 26 ]

Interfacing the password store w Shib

bull DynamoDB has a low-level HTTP-based API plus numerous higher-level API

bindings (eg Java Python Javascript etc)

bull since we were already using JAAS we developed a simple JAAS module

based on Jan Oppolzerrsquos jaas-rdbms-hashed [2]

bull not much effort

ndash had to adapt the Utils class (which performs password hashing) to use

PBKDF2WithHmacSHA256 instead of SHA256

ndash created a DynamoDB client factory that uses synchronized HashMap to allow for

multiple JAAS DynamoDB login configs each with their own client connection pool

ndash implement login() method of javaxsecurityauthspiLoginModule to

interface with DynamoDB

[ 27 ]

Add new JAAS configuration

bull create a jar for our JAAS module amp drop it in Shib IdP distributionrsquos webappsWEB-INFlib folder

bull add following to confauthnjaasconfig

ECPPasswordAuth eduarizonauitssiajaasdynamodbDynamoDBLogin requiredregion=us-west-2table=o365-app-pwpartitionKey=netidsortKey=hashedPwpwSalt=random stringcacheId=ddb

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 11: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 11 ]

Shibboleth mdash The Sugru reg of SSO

[ 12 ]

Shibboleth mdash The Sugru reg of SSO

[ 13 ]

Shibboleth mdash The Sugru reg of SSO

[ 14 ]

Shibboleth mdash The Sugru reg of SSO

[ 15 ]

Shibboleth IdP Environment

bull Shibboleth IdP v331 running in Docker containers

ndash Centos 7

ndash Oracle JDK 8

ndash Jetty 9

bull Authentication Components

ndash MultiFactorAuthnConfiguration

ndash DuoAuthnConfiguration

ndash JAASAuthnConfiguration

[ 16 ]

Challenge 1 ndash Authenticate via LDAP BIND against 3 disjoint AD OUs

bull need to attempt authentications against 3 different OUs in Active Directory

bull OUs house separate user populations

ndash normal users (NetIDs)

ndash service accounts

ndash delegated domain admins

bull need to keep track of which OU user was authenticated against in order to use

different MFA configurations in subsequent step

[ 17 ]

JAAS to the rescue

bull JAAS = Java Authentication and Authorization Service

bull (from the Shibboleth Wiki) JAAS is a desktop authentication mechanism in

Java that has been commonly misappropriated as a server-side technology

bull PAM-like can have multiple configurations that are tried in succession until

one succeeds

[ 18 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

[ 19 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct base DNs

(could be distinct servers)

[ 20 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct LDAP connection pools

[ 21 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

[ 22 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

[ 23 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

Build app password service (agrave la Google or Azure MFA) which stores

application-specific passwords in a separate store and requires same level of

authentication as logging-in to O365

[ 24 ]

Configuring ECP in Shibboleth

bull what is ECP

ndash Enhanced Client or Proxy

ndash client that is not a browser

ndash The ECP profile is an adaptation of the SAML profile used for Browser SSO with the

parts that were designed around the limitations of a browser removed

bull configuring ECP for password-based authN is pretty straightforward and is

described on Shibboleth wiki [1]

bull how do we know to access app password store for authentication credentials

when ECP binding is used (will get to this in next challenge)

[ 25 ]

App Password Store

bull requirements are simple

ndash user can have unlimited number of app passwords

ndash passwords are stored in hashed format (using PBKDF2)

ndash store createdOn lastUsed and simple text description (eg name of app that will be using password)

bull where to store passwords

ndash Shib IdP will have multiple nodes (for HA) so we need a shared data source

ndash dedicated relational DB seems like overkill

ndash ended up settling on AWS DynamoDB

bull will be running Shib IdP hosts in AWS

bull minimal costmaintenanceeffort

bull not really worried about backing up data (beyond replication for HA purposes)

bull app password management application

ndash serverless NodeJS application also running in AWS (using Lambda and API Gateway)

ndash use Passportjs for SAML authentication against our IdP

ndash use AWS Javascript SDK to interface with DynamoDB

[ 26 ]

Interfacing the password store w Shib

bull DynamoDB has a low-level HTTP-based API plus numerous higher-level API

bindings (eg Java Python Javascript etc)

bull since we were already using JAAS we developed a simple JAAS module

based on Jan Oppolzerrsquos jaas-rdbms-hashed [2]

bull not much effort

ndash had to adapt the Utils class (which performs password hashing) to use

PBKDF2WithHmacSHA256 instead of SHA256

ndash created a DynamoDB client factory that uses synchronized HashMap to allow for

multiple JAAS DynamoDB login configs each with their own client connection pool

ndash implement login() method of javaxsecurityauthspiLoginModule to

interface with DynamoDB

[ 27 ]

Add new JAAS configuration

bull create a jar for our JAAS module amp drop it in Shib IdP distributionrsquos webappsWEB-INFlib folder

bull add following to confauthnjaasconfig

ECPPasswordAuth eduarizonauitssiajaasdynamodbDynamoDBLogin requiredregion=us-west-2table=o365-app-pwpartitionKey=netidsortKey=hashedPwpwSalt=random stringcacheId=ddb

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 12: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 12 ]

Shibboleth mdash The Sugru reg of SSO

[ 13 ]

Shibboleth mdash The Sugru reg of SSO

[ 14 ]

Shibboleth mdash The Sugru reg of SSO

[ 15 ]

Shibboleth IdP Environment

bull Shibboleth IdP v331 running in Docker containers

ndash Centos 7

ndash Oracle JDK 8

ndash Jetty 9

bull Authentication Components

ndash MultiFactorAuthnConfiguration

ndash DuoAuthnConfiguration

ndash JAASAuthnConfiguration

[ 16 ]

Challenge 1 ndash Authenticate via LDAP BIND against 3 disjoint AD OUs

bull need to attempt authentications against 3 different OUs in Active Directory

bull OUs house separate user populations

ndash normal users (NetIDs)

ndash service accounts

ndash delegated domain admins

bull need to keep track of which OU user was authenticated against in order to use

different MFA configurations in subsequent step

[ 17 ]

JAAS to the rescue

bull JAAS = Java Authentication and Authorization Service

bull (from the Shibboleth Wiki) JAAS is a desktop authentication mechanism in

Java that has been commonly misappropriated as a server-side technology

bull PAM-like can have multiple configurations that are tried in succession until

one succeeds

[ 18 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

[ 19 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct base DNs

(could be distinct servers)

[ 20 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct LDAP connection pools

[ 21 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

[ 22 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

[ 23 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

Build app password service (agrave la Google or Azure MFA) which stores

application-specific passwords in a separate store and requires same level of

authentication as logging-in to O365

[ 24 ]

Configuring ECP in Shibboleth

bull what is ECP

ndash Enhanced Client or Proxy

ndash client that is not a browser

ndash The ECP profile is an adaptation of the SAML profile used for Browser SSO with the

parts that were designed around the limitations of a browser removed

bull configuring ECP for password-based authN is pretty straightforward and is

described on Shibboleth wiki [1]

bull how do we know to access app password store for authentication credentials

when ECP binding is used (will get to this in next challenge)

[ 25 ]

App Password Store

bull requirements are simple

ndash user can have unlimited number of app passwords

ndash passwords are stored in hashed format (using PBKDF2)

ndash store createdOn lastUsed and simple text description (eg name of app that will be using password)

bull where to store passwords

ndash Shib IdP will have multiple nodes (for HA) so we need a shared data source

ndash dedicated relational DB seems like overkill

ndash ended up settling on AWS DynamoDB

bull will be running Shib IdP hosts in AWS

bull minimal costmaintenanceeffort

bull not really worried about backing up data (beyond replication for HA purposes)

bull app password management application

ndash serverless NodeJS application also running in AWS (using Lambda and API Gateway)

ndash use Passportjs for SAML authentication against our IdP

ndash use AWS Javascript SDK to interface with DynamoDB

[ 26 ]

Interfacing the password store w Shib

bull DynamoDB has a low-level HTTP-based API plus numerous higher-level API

bindings (eg Java Python Javascript etc)

bull since we were already using JAAS we developed a simple JAAS module

based on Jan Oppolzerrsquos jaas-rdbms-hashed [2]

bull not much effort

ndash had to adapt the Utils class (which performs password hashing) to use

PBKDF2WithHmacSHA256 instead of SHA256

ndash created a DynamoDB client factory that uses synchronized HashMap to allow for

multiple JAAS DynamoDB login configs each with their own client connection pool

ndash implement login() method of javaxsecurityauthspiLoginModule to

interface with DynamoDB

[ 27 ]

Add new JAAS configuration

bull create a jar for our JAAS module amp drop it in Shib IdP distributionrsquos webappsWEB-INFlib folder

bull add following to confauthnjaasconfig

ECPPasswordAuth eduarizonauitssiajaasdynamodbDynamoDBLogin requiredregion=us-west-2table=o365-app-pwpartitionKey=netidsortKey=hashedPwpwSalt=random stringcacheId=ddb

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 13: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 13 ]

Shibboleth mdash The Sugru reg of SSO

[ 14 ]

Shibboleth mdash The Sugru reg of SSO

[ 15 ]

Shibboleth IdP Environment

bull Shibboleth IdP v331 running in Docker containers

ndash Centos 7

ndash Oracle JDK 8

ndash Jetty 9

bull Authentication Components

ndash MultiFactorAuthnConfiguration

ndash DuoAuthnConfiguration

ndash JAASAuthnConfiguration

[ 16 ]

Challenge 1 ndash Authenticate via LDAP BIND against 3 disjoint AD OUs

bull need to attempt authentications against 3 different OUs in Active Directory

bull OUs house separate user populations

ndash normal users (NetIDs)

ndash service accounts

ndash delegated domain admins

bull need to keep track of which OU user was authenticated against in order to use

different MFA configurations in subsequent step

[ 17 ]

JAAS to the rescue

bull JAAS = Java Authentication and Authorization Service

bull (from the Shibboleth Wiki) JAAS is a desktop authentication mechanism in

Java that has been commonly misappropriated as a server-side technology

bull PAM-like can have multiple configurations that are tried in succession until

one succeeds

[ 18 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

[ 19 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct base DNs

(could be distinct servers)

[ 20 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct LDAP connection pools

[ 21 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

[ 22 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

[ 23 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

Build app password service (agrave la Google or Azure MFA) which stores

application-specific passwords in a separate store and requires same level of

authentication as logging-in to O365

[ 24 ]

Configuring ECP in Shibboleth

bull what is ECP

ndash Enhanced Client or Proxy

ndash client that is not a browser

ndash The ECP profile is an adaptation of the SAML profile used for Browser SSO with the

parts that were designed around the limitations of a browser removed

bull configuring ECP for password-based authN is pretty straightforward and is

described on Shibboleth wiki [1]

bull how do we know to access app password store for authentication credentials

when ECP binding is used (will get to this in next challenge)

[ 25 ]

App Password Store

bull requirements are simple

ndash user can have unlimited number of app passwords

ndash passwords are stored in hashed format (using PBKDF2)

ndash store createdOn lastUsed and simple text description (eg name of app that will be using password)

bull where to store passwords

ndash Shib IdP will have multiple nodes (for HA) so we need a shared data source

ndash dedicated relational DB seems like overkill

ndash ended up settling on AWS DynamoDB

bull will be running Shib IdP hosts in AWS

bull minimal costmaintenanceeffort

bull not really worried about backing up data (beyond replication for HA purposes)

bull app password management application

ndash serverless NodeJS application also running in AWS (using Lambda and API Gateway)

ndash use Passportjs for SAML authentication against our IdP

ndash use AWS Javascript SDK to interface with DynamoDB

[ 26 ]

Interfacing the password store w Shib

bull DynamoDB has a low-level HTTP-based API plus numerous higher-level API

bindings (eg Java Python Javascript etc)

bull since we were already using JAAS we developed a simple JAAS module

based on Jan Oppolzerrsquos jaas-rdbms-hashed [2]

bull not much effort

ndash had to adapt the Utils class (which performs password hashing) to use

PBKDF2WithHmacSHA256 instead of SHA256

ndash created a DynamoDB client factory that uses synchronized HashMap to allow for

multiple JAAS DynamoDB login configs each with their own client connection pool

ndash implement login() method of javaxsecurityauthspiLoginModule to

interface with DynamoDB

[ 27 ]

Add new JAAS configuration

bull create a jar for our JAAS module amp drop it in Shib IdP distributionrsquos webappsWEB-INFlib folder

bull add following to confauthnjaasconfig

ECPPasswordAuth eduarizonauitssiajaasdynamodbDynamoDBLogin requiredregion=us-west-2table=o365-app-pwpartitionKey=netidsortKey=hashedPwpwSalt=random stringcacheId=ddb

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 14: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 14 ]

Shibboleth mdash The Sugru reg of SSO

[ 15 ]

Shibboleth IdP Environment

bull Shibboleth IdP v331 running in Docker containers

ndash Centos 7

ndash Oracle JDK 8

ndash Jetty 9

bull Authentication Components

ndash MultiFactorAuthnConfiguration

ndash DuoAuthnConfiguration

ndash JAASAuthnConfiguration

[ 16 ]

Challenge 1 ndash Authenticate via LDAP BIND against 3 disjoint AD OUs

bull need to attempt authentications against 3 different OUs in Active Directory

bull OUs house separate user populations

ndash normal users (NetIDs)

ndash service accounts

ndash delegated domain admins

bull need to keep track of which OU user was authenticated against in order to use

different MFA configurations in subsequent step

[ 17 ]

JAAS to the rescue

bull JAAS = Java Authentication and Authorization Service

bull (from the Shibboleth Wiki) JAAS is a desktop authentication mechanism in

Java that has been commonly misappropriated as a server-side technology

bull PAM-like can have multiple configurations that are tried in succession until

one succeeds

[ 18 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

[ 19 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct base DNs

(could be distinct servers)

[ 20 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct LDAP connection pools

[ 21 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

[ 22 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

[ 23 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

Build app password service (agrave la Google or Azure MFA) which stores

application-specific passwords in a separate store and requires same level of

authentication as logging-in to O365

[ 24 ]

Configuring ECP in Shibboleth

bull what is ECP

ndash Enhanced Client or Proxy

ndash client that is not a browser

ndash The ECP profile is an adaptation of the SAML profile used for Browser SSO with the

parts that were designed around the limitations of a browser removed

bull configuring ECP for password-based authN is pretty straightforward and is

described on Shibboleth wiki [1]

bull how do we know to access app password store for authentication credentials

when ECP binding is used (will get to this in next challenge)

[ 25 ]

App Password Store

bull requirements are simple

ndash user can have unlimited number of app passwords

ndash passwords are stored in hashed format (using PBKDF2)

ndash store createdOn lastUsed and simple text description (eg name of app that will be using password)

bull where to store passwords

ndash Shib IdP will have multiple nodes (for HA) so we need a shared data source

ndash dedicated relational DB seems like overkill

ndash ended up settling on AWS DynamoDB

bull will be running Shib IdP hosts in AWS

bull minimal costmaintenanceeffort

bull not really worried about backing up data (beyond replication for HA purposes)

bull app password management application

ndash serverless NodeJS application also running in AWS (using Lambda and API Gateway)

ndash use Passportjs for SAML authentication against our IdP

ndash use AWS Javascript SDK to interface with DynamoDB

[ 26 ]

Interfacing the password store w Shib

bull DynamoDB has a low-level HTTP-based API plus numerous higher-level API

bindings (eg Java Python Javascript etc)

bull since we were already using JAAS we developed a simple JAAS module

based on Jan Oppolzerrsquos jaas-rdbms-hashed [2]

bull not much effort

ndash had to adapt the Utils class (which performs password hashing) to use

PBKDF2WithHmacSHA256 instead of SHA256

ndash created a DynamoDB client factory that uses synchronized HashMap to allow for

multiple JAAS DynamoDB login configs each with their own client connection pool

ndash implement login() method of javaxsecurityauthspiLoginModule to

interface with DynamoDB

[ 27 ]

Add new JAAS configuration

bull create a jar for our JAAS module amp drop it in Shib IdP distributionrsquos webappsWEB-INFlib folder

bull add following to confauthnjaasconfig

ECPPasswordAuth eduarizonauitssiajaasdynamodbDynamoDBLogin requiredregion=us-west-2table=o365-app-pwpartitionKey=netidsortKey=hashedPwpwSalt=random stringcacheId=ddb

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 15: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 15 ]

Shibboleth IdP Environment

bull Shibboleth IdP v331 running in Docker containers

ndash Centos 7

ndash Oracle JDK 8

ndash Jetty 9

bull Authentication Components

ndash MultiFactorAuthnConfiguration

ndash DuoAuthnConfiguration

ndash JAASAuthnConfiguration

[ 16 ]

Challenge 1 ndash Authenticate via LDAP BIND against 3 disjoint AD OUs

bull need to attempt authentications against 3 different OUs in Active Directory

bull OUs house separate user populations

ndash normal users (NetIDs)

ndash service accounts

ndash delegated domain admins

bull need to keep track of which OU user was authenticated against in order to use

different MFA configurations in subsequent step

[ 17 ]

JAAS to the rescue

bull JAAS = Java Authentication and Authorization Service

bull (from the Shibboleth Wiki) JAAS is a desktop authentication mechanism in

Java that has been commonly misappropriated as a server-side technology

bull PAM-like can have multiple configurations that are tried in succession until

one succeeds

[ 18 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

[ 19 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct base DNs

(could be distinct servers)

[ 20 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct LDAP connection pools

[ 21 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

[ 22 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

[ 23 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

Build app password service (agrave la Google or Azure MFA) which stores

application-specific passwords in a separate store and requires same level of

authentication as logging-in to O365

[ 24 ]

Configuring ECP in Shibboleth

bull what is ECP

ndash Enhanced Client or Proxy

ndash client that is not a browser

ndash The ECP profile is an adaptation of the SAML profile used for Browser SSO with the

parts that were designed around the limitations of a browser removed

bull configuring ECP for password-based authN is pretty straightforward and is

described on Shibboleth wiki [1]

bull how do we know to access app password store for authentication credentials

when ECP binding is used (will get to this in next challenge)

[ 25 ]

App Password Store

bull requirements are simple

ndash user can have unlimited number of app passwords

ndash passwords are stored in hashed format (using PBKDF2)

ndash store createdOn lastUsed and simple text description (eg name of app that will be using password)

bull where to store passwords

ndash Shib IdP will have multiple nodes (for HA) so we need a shared data source

ndash dedicated relational DB seems like overkill

ndash ended up settling on AWS DynamoDB

bull will be running Shib IdP hosts in AWS

bull minimal costmaintenanceeffort

bull not really worried about backing up data (beyond replication for HA purposes)

bull app password management application

ndash serverless NodeJS application also running in AWS (using Lambda and API Gateway)

ndash use Passportjs for SAML authentication against our IdP

ndash use AWS Javascript SDK to interface with DynamoDB

[ 26 ]

Interfacing the password store w Shib

bull DynamoDB has a low-level HTTP-based API plus numerous higher-level API

bindings (eg Java Python Javascript etc)

bull since we were already using JAAS we developed a simple JAAS module

based on Jan Oppolzerrsquos jaas-rdbms-hashed [2]

bull not much effort

ndash had to adapt the Utils class (which performs password hashing) to use

PBKDF2WithHmacSHA256 instead of SHA256

ndash created a DynamoDB client factory that uses synchronized HashMap to allow for

multiple JAAS DynamoDB login configs each with their own client connection pool

ndash implement login() method of javaxsecurityauthspiLoginModule to

interface with DynamoDB

[ 27 ]

Add new JAAS configuration

bull create a jar for our JAAS module amp drop it in Shib IdP distributionrsquos webappsWEB-INFlib folder

bull add following to confauthnjaasconfig

ECPPasswordAuth eduarizonauitssiajaasdynamodbDynamoDBLogin requiredregion=us-west-2table=o365-app-pwpartitionKey=netidsortKey=hashedPwpwSalt=random stringcacheId=ddb

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 16: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 16 ]

Challenge 1 ndash Authenticate via LDAP BIND against 3 disjoint AD OUs

bull need to attempt authentications against 3 different OUs in Active Directory

bull OUs house separate user populations

ndash normal users (NetIDs)

ndash service accounts

ndash delegated domain admins

bull need to keep track of which OU user was authenticated against in order to use

different MFA configurations in subsequent step

[ 17 ]

JAAS to the rescue

bull JAAS = Java Authentication and Authorization Service

bull (from the Shibboleth Wiki) JAAS is a desktop authentication mechanism in

Java that has been commonly misappropriated as a server-side technology

bull PAM-like can have multiple configurations that are tried in succession until

one succeeds

[ 18 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

[ 19 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct base DNs

(could be distinct servers)

[ 20 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct LDAP connection pools

[ 21 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

[ 22 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

[ 23 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

Build app password service (agrave la Google or Azure MFA) which stores

application-specific passwords in a separate store and requires same level of

authentication as logging-in to O365

[ 24 ]

Configuring ECP in Shibboleth

bull what is ECP

ndash Enhanced Client or Proxy

ndash client that is not a browser

ndash The ECP profile is an adaptation of the SAML profile used for Browser SSO with the

parts that were designed around the limitations of a browser removed

bull configuring ECP for password-based authN is pretty straightforward and is

described on Shibboleth wiki [1]

bull how do we know to access app password store for authentication credentials

when ECP binding is used (will get to this in next challenge)

[ 25 ]

App Password Store

bull requirements are simple

ndash user can have unlimited number of app passwords

ndash passwords are stored in hashed format (using PBKDF2)

ndash store createdOn lastUsed and simple text description (eg name of app that will be using password)

bull where to store passwords

ndash Shib IdP will have multiple nodes (for HA) so we need a shared data source

ndash dedicated relational DB seems like overkill

ndash ended up settling on AWS DynamoDB

bull will be running Shib IdP hosts in AWS

bull minimal costmaintenanceeffort

bull not really worried about backing up data (beyond replication for HA purposes)

bull app password management application

ndash serverless NodeJS application also running in AWS (using Lambda and API Gateway)

ndash use Passportjs for SAML authentication against our IdP

ndash use AWS Javascript SDK to interface with DynamoDB

[ 26 ]

Interfacing the password store w Shib

bull DynamoDB has a low-level HTTP-based API plus numerous higher-level API

bindings (eg Java Python Javascript etc)

bull since we were already using JAAS we developed a simple JAAS module

based on Jan Oppolzerrsquos jaas-rdbms-hashed [2]

bull not much effort

ndash had to adapt the Utils class (which performs password hashing) to use

PBKDF2WithHmacSHA256 instead of SHA256

ndash created a DynamoDB client factory that uses synchronized HashMap to allow for

multiple JAAS DynamoDB login configs each with their own client connection pool

ndash implement login() method of javaxsecurityauthspiLoginModule to

interface with DynamoDB

[ 27 ]

Add new JAAS configuration

bull create a jar for our JAAS module amp drop it in Shib IdP distributionrsquos webappsWEB-INFlib folder

bull add following to confauthnjaasconfig

ECPPasswordAuth eduarizonauitssiajaasdynamodbDynamoDBLogin requiredregion=us-west-2table=o365-app-pwpartitionKey=netidsortKey=hashedPwpwSalt=random stringcacheId=ddb

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 17: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 17 ]

JAAS to the rescue

bull JAAS = Java Authentication and Authorization Service

bull (from the Shibboleth Wiki) JAAS is a desktop authentication mechanism in

Java that has been commonly misappropriated as a server-side technology

bull PAM-like can have multiple configurations that are tried in succession until

one succeeds

[ 18 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

[ 19 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct base DNs

(could be distinct servers)

[ 20 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct LDAP connection pools

[ 21 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

[ 22 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

[ 23 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

Build app password service (agrave la Google or Azure MFA) which stores

application-specific passwords in a separate store and requires same level of

authentication as logging-in to O365

[ 24 ]

Configuring ECP in Shibboleth

bull what is ECP

ndash Enhanced Client or Proxy

ndash client that is not a browser

ndash The ECP profile is an adaptation of the SAML profile used for Browser SSO with the

parts that were designed around the limitations of a browser removed

bull configuring ECP for password-based authN is pretty straightforward and is

described on Shibboleth wiki [1]

bull how do we know to access app password store for authentication credentials

when ECP binding is used (will get to this in next challenge)

[ 25 ]

App Password Store

bull requirements are simple

ndash user can have unlimited number of app passwords

ndash passwords are stored in hashed format (using PBKDF2)

ndash store createdOn lastUsed and simple text description (eg name of app that will be using password)

bull where to store passwords

ndash Shib IdP will have multiple nodes (for HA) so we need a shared data source

ndash dedicated relational DB seems like overkill

ndash ended up settling on AWS DynamoDB

bull will be running Shib IdP hosts in AWS

bull minimal costmaintenanceeffort

bull not really worried about backing up data (beyond replication for HA purposes)

bull app password management application

ndash serverless NodeJS application also running in AWS (using Lambda and API Gateway)

ndash use Passportjs for SAML authentication against our IdP

ndash use AWS Javascript SDK to interface with DynamoDB

[ 26 ]

Interfacing the password store w Shib

bull DynamoDB has a low-level HTTP-based API plus numerous higher-level API

bindings (eg Java Python Javascript etc)

bull since we were already using JAAS we developed a simple JAAS module

based on Jan Oppolzerrsquos jaas-rdbms-hashed [2]

bull not much effort

ndash had to adapt the Utils class (which performs password hashing) to use

PBKDF2WithHmacSHA256 instead of SHA256

ndash created a DynamoDB client factory that uses synchronized HashMap to allow for

multiple JAAS DynamoDB login configs each with their own client connection pool

ndash implement login() method of javaxsecurityauthspiLoginModule to

interface with DynamoDB

[ 27 ]

Add new JAAS configuration

bull create a jar for our JAAS module amp drop it in Shib IdP distributionrsquos webappsWEB-INFlib folder

bull add following to confauthnjaasconfig

ECPPasswordAuth eduarizonauitssiajaasdynamodbDynamoDBLogin requiredregion=us-west-2table=o365-app-pwpartitionKey=netidsortKey=hashedPwpwSalt=random stringcacheId=ddb

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 18: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 18 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

[ 19 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct base DNs

(could be distinct servers)

[ 20 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct LDAP connection pools

[ 21 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

[ 22 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

[ 23 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

Build app password service (agrave la Google or Azure MFA) which stores

application-specific passwords in a separate store and requires same level of

authentication as logging-in to O365

[ 24 ]

Configuring ECP in Shibboleth

bull what is ECP

ndash Enhanced Client or Proxy

ndash client that is not a browser

ndash The ECP profile is an adaptation of the SAML profile used for Browser SSO with the

parts that were designed around the limitations of a browser removed

bull configuring ECP for password-based authN is pretty straightforward and is

described on Shibboleth wiki [1]

bull how do we know to access app password store for authentication credentials

when ECP binding is used (will get to this in next challenge)

[ 25 ]

App Password Store

bull requirements are simple

ndash user can have unlimited number of app passwords

ndash passwords are stored in hashed format (using PBKDF2)

ndash store createdOn lastUsed and simple text description (eg name of app that will be using password)

bull where to store passwords

ndash Shib IdP will have multiple nodes (for HA) so we need a shared data source

ndash dedicated relational DB seems like overkill

ndash ended up settling on AWS DynamoDB

bull will be running Shib IdP hosts in AWS

bull minimal costmaintenanceeffort

bull not really worried about backing up data (beyond replication for HA purposes)

bull app password management application

ndash serverless NodeJS application also running in AWS (using Lambda and API Gateway)

ndash use Passportjs for SAML authentication against our IdP

ndash use AWS Javascript SDK to interface with DynamoDB

[ 26 ]

Interfacing the password store w Shib

bull DynamoDB has a low-level HTTP-based API plus numerous higher-level API

bindings (eg Java Python Javascript etc)

bull since we were already using JAAS we developed a simple JAAS module

based on Jan Oppolzerrsquos jaas-rdbms-hashed [2]

bull not much effort

ndash had to adapt the Utils class (which performs password hashing) to use

PBKDF2WithHmacSHA256 instead of SHA256

ndash created a DynamoDB client factory that uses synchronized HashMap to allow for

multiple JAAS DynamoDB login configs each with their own client connection pool

ndash implement login() method of javaxsecurityauthspiLoginModule to

interface with DynamoDB

[ 27 ]

Add new JAAS configuration

bull create a jar for our JAAS module amp drop it in Shib IdP distributionrsquos webappsWEB-INFlib folder

bull add following to confauthnjaasconfig

ECPPasswordAuth eduarizonauitssiajaasdynamodbDynamoDBLogin requiredregion=us-west-2table=o365-app-pwpartitionKey=netidsortKey=hashedPwpwSalt=random stringcacheId=ddb

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 19: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 19 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct base DNs

(could be distinct servers)

[ 20 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct LDAP connection pools

[ 21 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

[ 22 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

[ 23 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

Build app password service (agrave la Google or Azure MFA) which stores

application-specific passwords in a separate store and requires same level of

authentication as logging-in to O365

[ 24 ]

Configuring ECP in Shibboleth

bull what is ECP

ndash Enhanced Client or Proxy

ndash client that is not a browser

ndash The ECP profile is an adaptation of the SAML profile used for Browser SSO with the

parts that were designed around the limitations of a browser removed

bull configuring ECP for password-based authN is pretty straightforward and is

described on Shibboleth wiki [1]

bull how do we know to access app password store for authentication credentials

when ECP binding is used (will get to this in next challenge)

[ 25 ]

App Password Store

bull requirements are simple

ndash user can have unlimited number of app passwords

ndash passwords are stored in hashed format (using PBKDF2)

ndash store createdOn lastUsed and simple text description (eg name of app that will be using password)

bull where to store passwords

ndash Shib IdP will have multiple nodes (for HA) so we need a shared data source

ndash dedicated relational DB seems like overkill

ndash ended up settling on AWS DynamoDB

bull will be running Shib IdP hosts in AWS

bull minimal costmaintenanceeffort

bull not really worried about backing up data (beyond replication for HA purposes)

bull app password management application

ndash serverless NodeJS application also running in AWS (using Lambda and API Gateway)

ndash use Passportjs for SAML authentication against our IdP

ndash use AWS Javascript SDK to interface with DynamoDB

[ 26 ]

Interfacing the password store w Shib

bull DynamoDB has a low-level HTTP-based API plus numerous higher-level API

bindings (eg Java Python Javascript etc)

bull since we were already using JAAS we developed a simple JAAS module

based on Jan Oppolzerrsquos jaas-rdbms-hashed [2]

bull not much effort

ndash had to adapt the Utils class (which performs password hashing) to use

PBKDF2WithHmacSHA256 instead of SHA256

ndash created a DynamoDB client factory that uses synchronized HashMap to allow for

multiple JAAS DynamoDB login configs each with their own client connection pool

ndash implement login() method of javaxsecurityauthspiLoginModule to

interface with DynamoDB

[ 27 ]

Add new JAAS configuration

bull create a jar for our JAAS module amp drop it in Shib IdP distributionrsquos webappsWEB-INFlib folder

bull add following to confauthnjaasconfig

ECPPasswordAuth eduarizonauitssiajaasdynamodbDynamoDBLogin requiredregion=us-west-2table=o365-app-pwpartitionKey=netidsortKey=hashedPwpwSalt=random stringcacheId=ddb

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 20: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 20 ]

jaasconfigCatnetNetIdAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=NetIDDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-netid-pool

CatnetAdminAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=AdminDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-admin-pool

CatnetSvcAcctAuth orgldaptivejaasLdapLoginModule requiredldapUrl=ldapsactivedirectoryarizonaedu636baseDn=OU=RCUDC=ArizonaDC=edubindDn=CN=__ua-shibb-bindOU=Service AccountsDC=ArizonaDC=edubindCredential=ltpasswordgtuseStartTLS=falsecredentialConfig=trustCertificates=fileoptshibboleth-idpcredentialsad-cert-chainpemuserFilter=(sAMAccountName=user)dnResolver=orgldaptiveauthPooledSearchDnResolverauthenticationHandler=orgldaptiveauthPooledBindAuthenticationHandlerminPoolSize=3maxPoolSize=10validatePeriodically=truevalidator=orgldaptivepoolSearchValidatorpruneStrategy=orgldaptivepoolIdlePruneStrategyprunePeriod=60000idleTime=120000subtreeSearch=truecacheId=catnet-svcacct-pool

Distinct LDAP connection pools

[ 21 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

[ 22 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

[ 23 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

Build app password service (agrave la Google or Azure MFA) which stores

application-specific passwords in a separate store and requires same level of

authentication as logging-in to O365

[ 24 ]

Configuring ECP in Shibboleth

bull what is ECP

ndash Enhanced Client or Proxy

ndash client that is not a browser

ndash The ECP profile is an adaptation of the SAML profile used for Browser SSO with the

parts that were designed around the limitations of a browser removed

bull configuring ECP for password-based authN is pretty straightforward and is

described on Shibboleth wiki [1]

bull how do we know to access app password store for authentication credentials

when ECP binding is used (will get to this in next challenge)

[ 25 ]

App Password Store

bull requirements are simple

ndash user can have unlimited number of app passwords

ndash passwords are stored in hashed format (using PBKDF2)

ndash store createdOn lastUsed and simple text description (eg name of app that will be using password)

bull where to store passwords

ndash Shib IdP will have multiple nodes (for HA) so we need a shared data source

ndash dedicated relational DB seems like overkill

ndash ended up settling on AWS DynamoDB

bull will be running Shib IdP hosts in AWS

bull minimal costmaintenanceeffort

bull not really worried about backing up data (beyond replication for HA purposes)

bull app password management application

ndash serverless NodeJS application also running in AWS (using Lambda and API Gateway)

ndash use Passportjs for SAML authentication against our IdP

ndash use AWS Javascript SDK to interface with DynamoDB

[ 26 ]

Interfacing the password store w Shib

bull DynamoDB has a low-level HTTP-based API plus numerous higher-level API

bindings (eg Java Python Javascript etc)

bull since we were already using JAAS we developed a simple JAAS module

based on Jan Oppolzerrsquos jaas-rdbms-hashed [2]

bull not much effort

ndash had to adapt the Utils class (which performs password hashing) to use

PBKDF2WithHmacSHA256 instead of SHA256

ndash created a DynamoDB client factory that uses synchronized HashMap to allow for

multiple JAAS DynamoDB login configs each with their own client connection pool

ndash implement login() method of javaxsecurityauthspiLoginModule to

interface with DynamoDB

[ 27 ]

Add new JAAS configuration

bull create a jar for our JAAS module amp drop it in Shib IdP distributionrsquos webappsWEB-INFlib folder

bull add following to confauthnjaasconfig

ECPPasswordAuth eduarizonauitssiajaasdynamodbDynamoDBLogin requiredregion=us-west-2table=o365-app-pwpartitionKey=netidsortKey=hashedPwpwSalt=random stringcacheId=ddb

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 21: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 21 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

[ 22 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

[ 23 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

Build app password service (agrave la Google or Azure MFA) which stores

application-specific passwords in a separate store and requires same level of

authentication as logging-in to O365

[ 24 ]

Configuring ECP in Shibboleth

bull what is ECP

ndash Enhanced Client or Proxy

ndash client that is not a browser

ndash The ECP profile is an adaptation of the SAML profile used for Browser SSO with the

parts that were designed around the limitations of a browser removed

bull configuring ECP for password-based authN is pretty straightforward and is

described on Shibboleth wiki [1]

bull how do we know to access app password store for authentication credentials

when ECP binding is used (will get to this in next challenge)

[ 25 ]

App Password Store

bull requirements are simple

ndash user can have unlimited number of app passwords

ndash passwords are stored in hashed format (using PBKDF2)

ndash store createdOn lastUsed and simple text description (eg name of app that will be using password)

bull where to store passwords

ndash Shib IdP will have multiple nodes (for HA) so we need a shared data source

ndash dedicated relational DB seems like overkill

ndash ended up settling on AWS DynamoDB

bull will be running Shib IdP hosts in AWS

bull minimal costmaintenanceeffort

bull not really worried about backing up data (beyond replication for HA purposes)

bull app password management application

ndash serverless NodeJS application also running in AWS (using Lambda and API Gateway)

ndash use Passportjs for SAML authentication against our IdP

ndash use AWS Javascript SDK to interface with DynamoDB

[ 26 ]

Interfacing the password store w Shib

bull DynamoDB has a low-level HTTP-based API plus numerous higher-level API

bindings (eg Java Python Javascript etc)

bull since we were already using JAAS we developed a simple JAAS module

based on Jan Oppolzerrsquos jaas-rdbms-hashed [2]

bull not much effort

ndash had to adapt the Utils class (which performs password hashing) to use

PBKDF2WithHmacSHA256 instead of SHA256

ndash created a DynamoDB client factory that uses synchronized HashMap to allow for

multiple JAAS DynamoDB login configs each with their own client connection pool

ndash implement login() method of javaxsecurityauthspiLoginModule to

interface with DynamoDB

[ 27 ]

Add new JAAS configuration

bull create a jar for our JAAS module amp drop it in Shib IdP distributionrsquos webappsWEB-INFlib folder

bull add following to confauthnjaasconfig

ECPPasswordAuth eduarizonauitssiajaasdynamodbDynamoDBLogin requiredregion=us-west-2table=o365-app-pwpartitionKey=netidsortKey=hashedPwpwSalt=random stringcacheId=ddb

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 22: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 22 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

[ 23 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

Build app password service (agrave la Google or Azure MFA) which stores

application-specific passwords in a separate store and requires same level of

authentication as logging-in to O365

[ 24 ]

Configuring ECP in Shibboleth

bull what is ECP

ndash Enhanced Client or Proxy

ndash client that is not a browser

ndash The ECP profile is an adaptation of the SAML profile used for Browser SSO with the

parts that were designed around the limitations of a browser removed

bull configuring ECP for password-based authN is pretty straightforward and is

described on Shibboleth wiki [1]

bull how do we know to access app password store for authentication credentials

when ECP binding is used (will get to this in next challenge)

[ 25 ]

App Password Store

bull requirements are simple

ndash user can have unlimited number of app passwords

ndash passwords are stored in hashed format (using PBKDF2)

ndash store createdOn lastUsed and simple text description (eg name of app that will be using password)

bull where to store passwords

ndash Shib IdP will have multiple nodes (for HA) so we need a shared data source

ndash dedicated relational DB seems like overkill

ndash ended up settling on AWS DynamoDB

bull will be running Shib IdP hosts in AWS

bull minimal costmaintenanceeffort

bull not really worried about backing up data (beyond replication for HA purposes)

bull app password management application

ndash serverless NodeJS application also running in AWS (using Lambda and API Gateway)

ndash use Passportjs for SAML authentication against our IdP

ndash use AWS Javascript SDK to interface with DynamoDB

[ 26 ]

Interfacing the password store w Shib

bull DynamoDB has a low-level HTTP-based API plus numerous higher-level API

bindings (eg Java Python Javascript etc)

bull since we were already using JAAS we developed a simple JAAS module

based on Jan Oppolzerrsquos jaas-rdbms-hashed [2]

bull not much effort

ndash had to adapt the Utils class (which performs password hashing) to use

PBKDF2WithHmacSHA256 instead of SHA256

ndash created a DynamoDB client factory that uses synchronized HashMap to allow for

multiple JAAS DynamoDB login configs each with their own client connection pool

ndash implement login() method of javaxsecurityauthspiLoginModule to

interface with DynamoDB

[ 27 ]

Add new JAAS configuration

bull create a jar for our JAAS module amp drop it in Shib IdP distributionrsquos webappsWEB-INFlib folder

bull add following to confauthnjaasconfig

ECPPasswordAuth eduarizonauitssiajaasdynamodbDynamoDBLogin requiredregion=us-west-2table=o365-app-pwpartitionKey=netidsortKey=hashedPwpwSalt=random stringcacheId=ddb

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 23: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 23 ]

Challenge 2 ndash provide ECP access for legacy clients in secure way

bull need to allow older versions of Outlook POPIMAP clients etc to continue

authenticating against Office 365

bull no simple way for these clients to directly use MFA

bull donrsquot want to expose escape hatch to MFA enforcement

How do we tackle this challenge

Build app password service (agrave la Google or Azure MFA) which stores

application-specific passwords in a separate store and requires same level of

authentication as logging-in to O365

[ 24 ]

Configuring ECP in Shibboleth

bull what is ECP

ndash Enhanced Client or Proxy

ndash client that is not a browser

ndash The ECP profile is an adaptation of the SAML profile used for Browser SSO with the

parts that were designed around the limitations of a browser removed

bull configuring ECP for password-based authN is pretty straightforward and is

described on Shibboleth wiki [1]

bull how do we know to access app password store for authentication credentials

when ECP binding is used (will get to this in next challenge)

[ 25 ]

App Password Store

bull requirements are simple

ndash user can have unlimited number of app passwords

ndash passwords are stored in hashed format (using PBKDF2)

ndash store createdOn lastUsed and simple text description (eg name of app that will be using password)

bull where to store passwords

ndash Shib IdP will have multiple nodes (for HA) so we need a shared data source

ndash dedicated relational DB seems like overkill

ndash ended up settling on AWS DynamoDB

bull will be running Shib IdP hosts in AWS

bull minimal costmaintenanceeffort

bull not really worried about backing up data (beyond replication for HA purposes)

bull app password management application

ndash serverless NodeJS application also running in AWS (using Lambda and API Gateway)

ndash use Passportjs for SAML authentication against our IdP

ndash use AWS Javascript SDK to interface with DynamoDB

[ 26 ]

Interfacing the password store w Shib

bull DynamoDB has a low-level HTTP-based API plus numerous higher-level API

bindings (eg Java Python Javascript etc)

bull since we were already using JAAS we developed a simple JAAS module

based on Jan Oppolzerrsquos jaas-rdbms-hashed [2]

bull not much effort

ndash had to adapt the Utils class (which performs password hashing) to use

PBKDF2WithHmacSHA256 instead of SHA256

ndash created a DynamoDB client factory that uses synchronized HashMap to allow for

multiple JAAS DynamoDB login configs each with their own client connection pool

ndash implement login() method of javaxsecurityauthspiLoginModule to

interface with DynamoDB

[ 27 ]

Add new JAAS configuration

bull create a jar for our JAAS module amp drop it in Shib IdP distributionrsquos webappsWEB-INFlib folder

bull add following to confauthnjaasconfig

ECPPasswordAuth eduarizonauitssiajaasdynamodbDynamoDBLogin requiredregion=us-west-2table=o365-app-pwpartitionKey=netidsortKey=hashedPwpwSalt=random stringcacheId=ddb

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 24: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 24 ]

Configuring ECP in Shibboleth

bull what is ECP

ndash Enhanced Client or Proxy

ndash client that is not a browser

ndash The ECP profile is an adaptation of the SAML profile used for Browser SSO with the

parts that were designed around the limitations of a browser removed

bull configuring ECP for password-based authN is pretty straightforward and is

described on Shibboleth wiki [1]

bull how do we know to access app password store for authentication credentials

when ECP binding is used (will get to this in next challenge)

[ 25 ]

App Password Store

bull requirements are simple

ndash user can have unlimited number of app passwords

ndash passwords are stored in hashed format (using PBKDF2)

ndash store createdOn lastUsed and simple text description (eg name of app that will be using password)

bull where to store passwords

ndash Shib IdP will have multiple nodes (for HA) so we need a shared data source

ndash dedicated relational DB seems like overkill

ndash ended up settling on AWS DynamoDB

bull will be running Shib IdP hosts in AWS

bull minimal costmaintenanceeffort

bull not really worried about backing up data (beyond replication for HA purposes)

bull app password management application

ndash serverless NodeJS application also running in AWS (using Lambda and API Gateway)

ndash use Passportjs for SAML authentication against our IdP

ndash use AWS Javascript SDK to interface with DynamoDB

[ 26 ]

Interfacing the password store w Shib

bull DynamoDB has a low-level HTTP-based API plus numerous higher-level API

bindings (eg Java Python Javascript etc)

bull since we were already using JAAS we developed a simple JAAS module

based on Jan Oppolzerrsquos jaas-rdbms-hashed [2]

bull not much effort

ndash had to adapt the Utils class (which performs password hashing) to use

PBKDF2WithHmacSHA256 instead of SHA256

ndash created a DynamoDB client factory that uses synchronized HashMap to allow for

multiple JAAS DynamoDB login configs each with their own client connection pool

ndash implement login() method of javaxsecurityauthspiLoginModule to

interface with DynamoDB

[ 27 ]

Add new JAAS configuration

bull create a jar for our JAAS module amp drop it in Shib IdP distributionrsquos webappsWEB-INFlib folder

bull add following to confauthnjaasconfig

ECPPasswordAuth eduarizonauitssiajaasdynamodbDynamoDBLogin requiredregion=us-west-2table=o365-app-pwpartitionKey=netidsortKey=hashedPwpwSalt=random stringcacheId=ddb

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 25: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 25 ]

App Password Store

bull requirements are simple

ndash user can have unlimited number of app passwords

ndash passwords are stored in hashed format (using PBKDF2)

ndash store createdOn lastUsed and simple text description (eg name of app that will be using password)

bull where to store passwords

ndash Shib IdP will have multiple nodes (for HA) so we need a shared data source

ndash dedicated relational DB seems like overkill

ndash ended up settling on AWS DynamoDB

bull will be running Shib IdP hosts in AWS

bull minimal costmaintenanceeffort

bull not really worried about backing up data (beyond replication for HA purposes)

bull app password management application

ndash serverless NodeJS application also running in AWS (using Lambda and API Gateway)

ndash use Passportjs for SAML authentication against our IdP

ndash use AWS Javascript SDK to interface with DynamoDB

[ 26 ]

Interfacing the password store w Shib

bull DynamoDB has a low-level HTTP-based API plus numerous higher-level API

bindings (eg Java Python Javascript etc)

bull since we were already using JAAS we developed a simple JAAS module

based on Jan Oppolzerrsquos jaas-rdbms-hashed [2]

bull not much effort

ndash had to adapt the Utils class (which performs password hashing) to use

PBKDF2WithHmacSHA256 instead of SHA256

ndash created a DynamoDB client factory that uses synchronized HashMap to allow for

multiple JAAS DynamoDB login configs each with their own client connection pool

ndash implement login() method of javaxsecurityauthspiLoginModule to

interface with DynamoDB

[ 27 ]

Add new JAAS configuration

bull create a jar for our JAAS module amp drop it in Shib IdP distributionrsquos webappsWEB-INFlib folder

bull add following to confauthnjaasconfig

ECPPasswordAuth eduarizonauitssiajaasdynamodbDynamoDBLogin requiredregion=us-west-2table=o365-app-pwpartitionKey=netidsortKey=hashedPwpwSalt=random stringcacheId=ddb

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 26: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 26 ]

Interfacing the password store w Shib

bull DynamoDB has a low-level HTTP-based API plus numerous higher-level API

bindings (eg Java Python Javascript etc)

bull since we were already using JAAS we developed a simple JAAS module

based on Jan Oppolzerrsquos jaas-rdbms-hashed [2]

bull not much effort

ndash had to adapt the Utils class (which performs password hashing) to use

PBKDF2WithHmacSHA256 instead of SHA256

ndash created a DynamoDB client factory that uses synchronized HashMap to allow for

multiple JAAS DynamoDB login configs each with their own client connection pool

ndash implement login() method of javaxsecurityauthspiLoginModule to

interface with DynamoDB

[ 27 ]

Add new JAAS configuration

bull create a jar for our JAAS module amp drop it in Shib IdP distributionrsquos webappsWEB-INFlib folder

bull add following to confauthnjaasconfig

ECPPasswordAuth eduarizonauitssiajaasdynamodbDynamoDBLogin requiredregion=us-west-2table=o365-app-pwpartitionKey=netidsortKey=hashedPwpwSalt=random stringcacheId=ddb

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 27: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 27 ]

Add new JAAS configuration

bull create a jar for our JAAS module amp drop it in Shib IdP distributionrsquos webappsWEB-INFlib folder

bull add following to confauthnjaasconfig

ECPPasswordAuth eduarizonauitssiajaasdynamodbDynamoDBLogin requiredregion=us-west-2table=o365-app-pwpartitionKey=netidsortKey=hashedPwpwSalt=random stringcacheId=ddb

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 28: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 28 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 29: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 29 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 30: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 30 ]

Challenge 3 ndash Configure separate MFA policies per OU

bull need to use different Duo application integration for principals in each OU

bull regular users (NetIDs) enroll in Duo via custom University-branded portal

bull service accounts and OU admin accounts need to enroll via Duo Web UI

bull bonus challenge provide mechanism to allow administrative bypass of Duo

2FA in special situations

How do we tackle this challenge

Shib allows the use of a Function bean for dynamically returning a set of JAAS

configuration names at runtime along with an optional set of principal types We

use these principal types in the MFA authn flow

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 31: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 31 ]

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 32: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 32 ]

JAASLoginConfigurationsMapltutilmapgtltentry1gtltentry2gt

hellipltentryngt

JAASLoginConfigurationsltutillistgt

ltbeangtparent=shibbolethPair

ltpropertygtname=first

value=JAASConfigName

ltpropertygtname=second

ref=

ltbeangtclass=javaxsecurityauthSubject

bull constructor-arg1=falsebull constructor-arg2=refbull constructor-arg3=refbull constructor-arg4=ref

CustomPTSetltutilsetgtvalue-type=

javasecurityPrincipalltrefgtltrefgt

hellip

CustomSubjectPubCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

CustomSubjectPrivCredsltutilsetgt (empty)

value-type=javasecurityPrincipal

PasswordProtectedTransportPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTransport

NetIdDuoPTltbeangt

parent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfa

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 33: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 33 ]

jaas-authn-configxml additions

lt-- Custom Principal types for JAAS Login Config mapping --gtltbean id=PasswordProtectedTransportPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordProtectedTra

nsportgtltbean id=PasswordPT

parent=shibbolethSAML2AuthnContextClassRefcclassRef=urnoasisnamestcSAML20acclassesPasswordgt

ltbean id=NetIdDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassesnetidmfagt

ltbean id=CatnetDuoPTparent=shibbolethSAML2AuthnContextClassRefcclassRef=httparizonaeduacclassescatnetmfagt

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 34: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 34 ]

jaas-authn-configxml additions (cont)

lt-- lists of custom principal types for each login config --gtltutilset id=ECPPasswordAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgt

ltutilsetgtltutilset id=CatnetNetIdAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=NetIdDuoPTgt

ltutilsetgtltutilset id=CatnetAdminAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgtltutilset id=CatnetSvcAcctAuthPTSet value-type=javasecurityPrincipalgt

ltref bean=PasswordProtectedTransportPTgtltref bean=PasswordPTgtltref bean=CatnetDuoPTgt

ltutilsetgt

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 35: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 35 ]

jaas-authn-configxml additions (cont)

lt-- empty pub amp private credentials lists for Subjects --gtltutilset id=ECPPasswordAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=ECPPasswordAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetNetIdAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetAdminAuthSubjectPrivCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPubCreds

value-type=javasecurityPrincipalgtltutilset id=CatnetSvcAcctAuthSubjectPrivCreds

value-type=javasecurityPrincipalgt

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 36: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 36 ]

jaas-authn-configxml additions (cont)

lt-- javaxsecurityauthSubject beans for each login config --gtltbean id=ECPPasswordAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=ECPPasswordAuthPTSetgtltconstructor-arg ref=ECPPasswordAuthSubjectPubCredsgtltconstructor-arg ref=ECPPasswordAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetNetIdAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetNetIdAuthPTSetgtltconstructor-arg ref=CatnetNetIdAuthSubjectPubCredsgtltconstructor-arg ref=CatnetNetIdAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetAdminAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetAdminAuthPTSetgtltconstructor-arg ref=CatnetAdminAuthSubjectPubCredsgtltconstructor-arg ref=CatnetAdminAuthSubjectPrivCredsgt

ltbeangtltbean id=CatnetSvcAcctAuthSubject class=javaxsecurityauthSubjectgt

ltconstructor-arg value=falsegtltconstructor-arg ref=CatnetSvcAcctAuthPTSetgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPubCredsgtltconstructor-arg ref=CatnetSvcAcctAuthSubjectPrivCredsgt

ltbeangt

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 37: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 37 ]

jaas-authn-configxml additions (cont)

lt-- Collections of JAAS login configs to custom principal lists --gtltutillist id=JAASECPLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtECPPasswordAuthltvaluegtltpropertygtltproperty name=second ref=ECPPasswordAuthSubjectgt

ltbeangtltutillistgtltutillist id=JAASDefaultLoginConfigurationsgt

ltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetNetIdAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetNetIdAuthSubjectgtltbeangtltbean parent=shibbolethPairgtltproperty name=firstgtltvaluegtCatnetAdminAuthltvaluegtltpropertygt

ltproperty name=second ref=CatnetAdminAuthSubjectgtltbeangtltbean parent=shibbolethPairgt

ltproperty name=firstgtltvaluegtCatnetSvcAcctAuthltvaluegtltpropertygtltproperty name=second ref=CatnetSvcAcctAuthSubjectgt

ltbeangtltutillistgt

lt-- map of SAML Binding to JAAS login configurations lists --gtltutilmap id=JAASLoginConfigurationsMapgt

ltentry key=ECP value-ref=JAASECPLoginConfigurationsgtltentry key=default value-ref=JAASDefaultLoginConfigurationsgt

ltutilmapgt

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 38: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 38 ]

Scripting the JAAS LoginConfigStrategy

bull now that we have our JAASLoginConfigurationsMap we can pass it to the

shibbolethauthnJAASLoginConfigStrategy bean (introduced in Shib

IdP 330)ltbean id=shibbolethauthnJAASLoginConfigStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=JAASLoginConfigurationsMapgt

ltconstructor-arggtltvaluegt

lt[CDATA[ Check if SAML binding is ECP or default (anything else)auditCtx = inputgetSubcontext(netshibbolethidpprofilecontextAuditContext)samlAuditFields = Javatype(netshibbolethidpsamlprofileSAMLAuditFields)bindings = auditCtxgetFieldValues(samlAuditFieldsREQUEST_BINDING)iter = bindingsiterator()isECP = falsewhile (iterhasNext() ampamp isECP)

b = iternext()if (b === urnoasisnamestcSAML20bindingsSOAP)

isECP = true

if (isECP)

loginConfig = customget(ECP) else

loginConfig = customget(default)loginConfig

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 39: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 39 ]

MultiFactorAuthnConfiguration

bull The authnMFA login flow is literally the greatest thing since sliced bread

bull allows you to combine multiple login flow via script or code glue to provide highly-

customized composite flows

bull described in-depth on the wiki [3]

bull we define a shibbolethauthnMFATransitionMap that includes 2 steps our initial

password authentication and our (conditional) second-factor authentication (Duo)

ndash password authentication is managed by the authnPassword login flow

bull delegates authentication to JAAS backend

ndash second-factor authentication managed by authnDuo login flow based on conditional output of

inline script

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 40: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 40 ]

shibbolethauthnMFATransitionMap (mfa-authn-configxml)

ltutilmap id=shibbolethauthnMFATransitionMapgtlt-- First rule runs the Password login flow --gtltentry key=gt

ltbean parent=shibbolethauthnMFATransitionpnextFlow=authnPasswordgt

ltentrygt

lt--Second rule runs a function if Password succeeds

to determine whether Duo authn is required--gtltentry key=authnPasswordgt

ltbean parent=shibbolethauthnMFATransitionpnextFlowStrategy-ref=checkSecondFactorgt

ltentrygt

lt-- An implicit final rule will return whatever the final flowreturns --gt

ltutilmapgt

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 41: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 41 ]

checkSecondFactor inline script (mfa-authn-configxml)lt-- script to see if second factor is required --gtltbean id=checkSecondFactor parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=shibbolethAttributeResolverServicegtltconstructor-arggt

ltvaluegtlt[CDATA[

nextFlow = null

Check if password flow returned mfa supported principal typeauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)principals = passwordAuthResultgetSupportedPrincipals(Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)class)

iter = principalsiterator()while (nextFlow == null ampamp iterhasNext())

pr = iternext()if (prgetName()endsWith(mfa))

nextFlow = authnDuo

if user in bypass group dont pass to Duoif (nextFlow === authnDuo)

resCtx = inputgetSubcontext(netshibbolethidpattributeresolvercontextAttributeResolutionContext true)

Look up the usernameusernameLookupStrategyClass = Javatype(netshibbolethidpsessioncontextnavigateCanonicalUsernameLookupStrategy)usernameLookupStrategy = new usernameLookupStrategyClass()username = usernameLookupStrategyapply(input)resCtxsetPrincipal(username)

resolve the isMemberOf attributeresCtxresolveAttributes(custom)

Check for isMemberOf value that allows bypass of Duoattribute = resCtxgetResolvedIdPAttributes()get(isMemberOf)valueType = Javatype(netshibbolethidpattributeStringAttributeValue)if (attribute = null ampamp attributegetValues()contains(new valueType(arizonaeduservicesenterprisecatnet20shibbolethduo-bypass))) nextFlow = null

nextFlow pass control to second factor or end with the first

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 42: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 42 ]

How do we use different Duo configurations for different user types

bull once again Shibboleth has you covered

ndash multiple Integrations

ndash DuoIntegrationStrategy (dynamic determination of strategy at run-time)

ndash integration-specific principal sets (segregate categories of Duo auth based on principal type)

bull again described in detail on the wiki [4]

bull in UArsquos case we configured two netshibbolethidpauthnduoBasicDuoIntegration

beans

ndash each one tied to one of our custom principal types

bull httparizonaeduacclassesnetidmfa

bull httparizonaeduacclassescatnetmfa

ndash recall these principal types are set by the specific JAAS config which successfully authenticates

the user

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 43: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 43 ]

Duo multiple integrations and principal types additions (duo-authn-configxml)

lt-- Turn off default behavior in favor of integration-specific principals below --gtltutilconstant id=shibbolethauthnDuoaddDefaultPrincipals static-field=javalangBooleanFALSEgt

ltbeanid=DefaultDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpduoapiHostnonepapplicationKey=idpduoapplicationKeynonepintegrationKey=idpduointegrationKeynonepsecretKey=idpduosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassesnetidmfagt

ltlistgtltpropertygt

ltbeangt

ltbeanid=CatnetDuoclass=netshibbolethidpauthnduoBasicDuoIntegrationpAPIHost=idpcatnetOnlyDuoapiHostnonepapplicationKey=idpcatnetOnlyDuoapplicationKeynonepintegrationKey=idpcatnetOnlyDuointegrationKeynonepsecretKey=idpcatnetOnlyDuosecretKeynonegtltproperty name=supportedPrincipalsgt

ltlistgtltbean parent=shibbolethSAML2AuthnContextClassRef cclassRef=httparizonaeduacclassescatnetmfagt

ltlistgtltpropertygt

ltbeangt

ltutillist id=DuoIntegrationListgtltref bean=CatnetDuogtltref bean=DefaultDuogt

ltutillistgt

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 44: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 44 ]

scripted Duo integration strategy (duo-authn-configxml)

ltbean id=shibbolethauthnDuoDuoIntegrationStrategy parent=shibbolethContextFunctionsScripted factory-method=inlineScript pcustomObject-ref=DuoIntegrationListgtltconstructor-arggt

ltvaluegtlt[CDATA[

duo = nullauthCtx = inputgetSubcontext(netshibbolethidpauthncontextAuthenticationContext)mfaCtx = authCtxgetSubcontext(netshibbolethidpauthncontextMultiFactorAuthenticationContext)passwordAuthResult = mfaCtxgetActiveResults()get(authnPassword)var clz = Javatype(netshibbolethidpsamlauthnprincipalAuthnContextClassRefPrincipal)classprincipals = passwordAuthResultgetSupportedPrincipals(clz)

iter = customiterator()

while (duo == null ampamp iterhasNext()) duo = iternext()supportedPrincipals = duogetSupportedPrincipals(clz) check if we got a match based on RequestedPrincipalContext and check current result context if notthisDuo = duoduo = nullif (passwordAuthResult = null)

prIter = principalsiterator()supPrIter = supportedPrincipalsiterator()while (duo == null ampamp prIterhasNext())

pr = prIternext()while (duo == null ampamp supPrIterhasNext())

supPr = supPrIternext()if (prgetName() == supPrgetName())

duo = thisDuo

duo return appropriate Duo config

]]gtltvaluegt

ltconstructor-arggtltbeangt

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 45: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 45 ]

Staying Agile ndash Containerization and Cloud Deployment

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 46: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 46 ]

Agility Goals

bull want everything (configuration + code) in SCCS

bull avoid having to maintain updates to metadata configuration files etc on the individual IdP backends

bull minimize effort in deploying Shib IdP software updates

bull maximize flexibility in scaling Shib IdP backends

bull perform bluegreen deployments of IdP configurationcode changes

bull minimize managementcosts of support infrastructure needed for Shib IdP ecosystem eg

ndash relational databases

ndash HA middleware

ndash application server for app passwords

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 47: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 47 ]

Agility Decision 1 ndash Dockerize Shib IdP

bull in-house experience running Docker Containers

bull makes it easier to maintain deployable IdP along with configurationmetadata

in SCCS

bull luckily we didnrsquot have to re-invent the wheel

ndash Uniconrsquos shibboleth-idp-dockerized IdP base image [5]

ndash created own Dockerfile based on Uniconrsquos base image with a few modifications

bull removed SSL config from Jetty

bull used Oracle JVM instead of OpenJDK [6]

bull removed standard spymemcached jar (needed to use memcached as shared ticket cache) and

replaced with AWS Elasticache-enabled version

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 48: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 48 ]

Agility Decision 2 ndash run IdP containers in AWS ECS

bull ECS = EC2 Container Service

ndash Amazon EC2 Container Service (ECS) is a highly scalable high performance

container management service that supports Docker containers and allows you to

easily run applications on a managed cluster of Amazon EC2 instances

bull allows us to schedule number of IdP tasks (containers) based on load

resource utilization etc

bull versioning of tasks allows us to perform bluegreen deployments when

updating Shib IdP configuration or code

bull could be done equally well on top of container orchestration frameworks like

Kubernetes or Mesos

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 49: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 49 ]

ECS Cluster

Container Instance 1

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 50: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 50 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

Scaling

Policies

invokesfeeds

CloudWatch Metrics CloudWatch Alarms

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 51: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 51 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 52: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 52 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

CloudWatch Metrics CloudWatch Alarms

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 53: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 53 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 54: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 54 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 55: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 55 ]

ECS Cluster

Service ATask 1

Container Instance 1 Container Instance 2

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

Service ATask 3

Service ATask 4

CloudWatch Metrics CloudWatch Alarms

Service ATask 5

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 56: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 56 ]

ECS Cluster

Service ATask 1

Container Instance 1

1) 1 EC2 Container instance 1

Service A task

2) Increased load triggers alarm

which executes application auto-

scaling policy

3) ECS cluster metrics trigger EC2

auto-scaling policy

4) Further application load

increase executes

application auto-scaling

launching additional

service A tasks on new

EC2 container instance

Scaling

Policies

invokesfeeds

Service ATask 2

CloudWatch Metrics CloudWatch Alarms5) As load

decreases auto-

scaling can scale-in

service A tasks and

EC2 container

instances

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 57: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 57 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

ECS Cluster

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 58: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 58 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

ECS Cluster

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 59: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 59 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

ECS Cluster

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 60: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 60 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

ECS Cluster

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 61: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 61 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

ECS Cluster

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 62: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 62 ]

ALB

Task 1 Task 2

Task 1 Task 2

Service A

Service B

Container Instance 1 Container Instance 2

Service A

Task

Definition

version nECR

latest

Service A

Task

Definition

version n+1

1) New task definition version

created

2) Service A task version updated

Task 3 Task 4

3) ECS launches new Service A

tasks and registers them with ALB

4) ALB connection

draining on previous tasks

begins

5) As connections drained

ECS kills old tasks

ECS Cluster

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 63: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 63 ]

Agility Decision 3 ndash use AWS ElastiCache for MemcachedStorageService

bull need shared storage mechanism for session storage and replay cache

ndash have successfully used memcached for this in past

bull could have run memcached instances in Docker containers alongside IdPcontainers

ndash additional infrastructurecode to managemaintain

ndash memcached discovery problem as number of instances growshrink

bull offload memcached duties to AWS ElastiCache

ndash 3 x t2micro cache nodes (us-west-2) = ~$25mo (on-demand) or ~$13mo (reserved w 1 yrterm)

bull use AWSrsquo ElastiCache Cluster Java client [7]

ndash drop-in replacement for spymemcached jar

ndash supports ElastiCachersquos memcached auto-discovery enhancement

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 64: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 64 ]

Agility Decision 4 ndash use SAM for app password website

bull SAM = Serverless Application Model

ndash AWS specification for defining serverless applications in AWS

ndash built on top of existing AWS components like Lambda CloudFront and API Gateway

bull website is utility site ndash not used heavily but must always be accessible

bull written as SPA using AngularJS

ndash interacts with API written in Express (Nodejs application framework)

bull API deployed as Lambda function and exposed via API gateway

ndash Claudiajs used to deploy

bull Passportjs used for Shib authentication and session state stored in DynamoDB

bull use of Lambda + DynamoDB makes this solution essentially free for the amount of utilization we have

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 65: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 65 ]

Agility Decision 5 ndash use CloudFormation + Git

bull entire IdP environment specified and deployed via AWS CloudFormation

bull CloudFormation templates storedmaintained in git repository

bull changes to environment performed through CF change sets

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 66: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

[ 66 ]

[demo]

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks

Page 67: How The University of Arizona Addressed SSO for Office 365 · How The University of Arizona Addressed SSO for Office 365 Gary Windham Senior Enterprise Systems Architect, The University

Resources

bull [1] httpswikishibbolethnetconfluencedisplayIDP30ECPConfiguration

bull [2] httpsgithubcomJanOppolzerjaas-rdbms-hashed

bull [3] httpswikishibbolethnetconfluencedisplayIDP30MultiFactorAuthnConfiguration

bull [4] httpswikishibbolethnetconfluencedisplayIDP30DuoAuthnConfiguration

bull [5] httpsgithubcomUniconshibboleth-idp-dockerized

bull [6] httpsgithubcomUniconshibboleth-idp-dockerizedwikiSwitching-to-the-Oracle-JVM

bull [7] httpsgithubcomawslabsaws-elasticache-cluster-client-memcached-for-java

bull JAAS DynamoDB module httpsbitbucketorgua_siajaas-dynamodb

Thanks