{"action":"created","issue":{"url":"https://api.github.com/repos/Jasig/cas/issues/1496","repository_url":"https://api.github.com/repos/Jasig/cas","labels_url":"https://api.github.com/repos/Jasig/cas/issues/1496/labels{/name}","comments_url":"https://api.github.com/repos/Jasig/cas/issues/1496/comments","events_url":"https://api.github.com/repos/Jasig/cas/issues/1496/events","html_url":"https://github.com/Jasig/cas/pull/1496","id":130431849,"number":1496,"title":"Add support for MFA","user":{"login":"mmoayyed","id":1205228,"avatar_url":"https://avatars.githubusercontent.com/u/1205228?v=3","gravatar_id":"","url":"https://api.github.com/users/mmoayyed","html_url":"https://github.com/mmoayyed","followers_url":"https://api.github.com/users/mmoayyed/followers","following_url":"https://api.github.com/users/mmoayyed/following{/other_user}","gists_url":"https://api.github.com/users/mmoayyed/gists{/gist_id}","starred_url":"https://api.github.com/users/mmoayyed/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mmoayyed/subscriptions","organizations_url":"https://api.github.com/users/mmoayyed/orgs","repos_url":"https://api.github.com/users/mmoayyed/repos","events_url":"https://api.github.com/users/mmoayyed/events{/privacy}","received_events_url":"https://api.github.com/users/mmoayyed/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/Jasig/cas/labels/Authentication","name":"Authentication","color":"5319e7"},{"url":"https://api.github.com/repos/Jasig/cas/labels/Major","name":"Major","color":"eb6420"},{"url":"https://api.github.com/repos/Jasig/cas/labels/MFA","name":"MFA","color":"5319e7"},{"url":"https://api.github.com/repos/Jasig/cas/labels/New%20Feature","name":"New Feature","color":"207de5"}],"state":"open","locked":false,"assignee":{"login":"mmoayyed","id":1205228,"avatar_url":"https://avatars.githubusercontent.com/u/1205228?v=3","gravatar_id":"","url":"https://api.github.com/users/mmoayyed","html_url":"https://github.com/mmoayyed","followers_url":"https://api.github.com/users/mmoayyed/followers","following_url":"https://api.github.com/users/mmoayyed/following{/other_user}","gists_url":"https://api.github.com/users/mmoayyed/gists{/gist_id}","starred_url":"https://api.github.com/users/mmoayyed/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mmoayyed/subscriptions","organizations_url":"https://api.github.com/users/mmoayyed/orgs","repos_url":"https://api.github.com/users/mmoayyed/repos","events_url":"https://api.github.com/users/mmoayyed/events{/privacy}","received_events_url":"https://api.github.com/users/mmoayyed/received_events","type":"User","site_admin":false},"milestone":{"url":"https://api.github.com/repos/Jasig/cas/milestones/15","html_url":"https://github.com/Jasig/cas/milestones/5.0.0","labels_url":"https://api.github.com/repos/Jasig/cas/milestones/15/labels","id":1349862,"number":15,"title":"5.0.0","description":"CAS version 5.0.0 release","creator":{"login":"mmoayyed","id":1205228,"avatar_url":"https://avatars.githubusercontent.com/u/1205228?v=3","gravatar_id":"","url":"https://api.github.com/users/mmoayyed","html_url":"https://github.com/mmoayyed","followers_url":"https://api.github.com/users/mmoayyed/followers","following_url":"https://api.github.com/users/mmoayyed/following{/other_user}","gists_url":"https://api.github.com/users/mmoayyed/gists{/gist_id}","starred_url":"https://api.github.com/users/mmoayyed/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mmoayyed/subscriptions","organizations_url":"https://api.github.com/users/mmoayyed/orgs","repos_url":"https://api.github.com/users/mmoayyed/repos","events_url":"https://api.github.com/users/mmoayyed/events{/privacy}","received_events_url":"https://api.github.com/users/mmoayyed/received_events","type":"User","site_admin":false},"open_issues":15,"closed_issues":136,"state":"open","created_at":"2015-10-12T01:28:38Z","updated_at":"2016-03-19T19:19:00Z","due_on":"2016-05-19T07:00:00Z","closed_at":null},"comments":73,"created_at":"2016-02-01T17:46:43Z","updated_at":"2016-03-20T02:08:15Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/Jasig/cas/pulls/1496","html_url":"https://github.com/Jasig/cas/pull/1496","diff_url":"https://github.com/Jasig/cas/pull/1496.diff","patch_url":"https://github.com/Jasig/cas/pull/1496.patch"},"body":"Closes #572 \r\n\r\n# Multifactor Authentication (MFA)\r\n\r\nCAS provides a framework for multifactor authentication (MFA). The design philosophy for MFA support follows from the observation that institutional security policies with respect to MFA vary dramatically. We provide first class API support for authenticating multiple credentials and a policy framework around authentication. The components could be extended in a straightforward fashion to provide higher-level behaviors such as Webflow logic to assist, for example, a credential upgrade scenario where a SSO session is started by a weaker credential but a particular service demands re-authentication with a stronger credential.\r\n\r\nThe authentication subsystem in CAS natively supports handling multiple credentials. While the default login form and Webflow tier are designed for the simple case of accepting a single credential, all core API components that interface with the authentication subsystem accept one or more credentials to authenticate.\r\n\r\n## Supported Providers\r\n\r\n### Duo Security\r\n\r\nConfigure authentication per instructions [here] (DuoSecurity-Authentication.html). \r\n\r\n| Field                | Description\r\n|----------------------|---------------------------------\r\n| `provider`           | `duoAuthenticationProvider` |\r\n| `id`                 | `mfa-duo` |\r\n\r\n### YubiKey\r\n\r\nConfigure authentication per instructions [here] (YubiKey-Authentication.html). \r\n\r\n| Field                | Description\r\n|----------------------|---------------------------------\r\n| `provider`           | `yubikeyAuthenticationProvider`\r\n| `id`                 | `mfa-yubikey`\r\n\r\n### RSA/RADIUS\r\n\r\nConfigure authentication per instructions [here] (RADIUS-Authentication.html). \r\n\r\n| Field                | Description\r\n|----------------------|---------------------------------\r\n| `provider`           | `radiusAuthenticationProvider`\r\n| `id`                 | `mfa-radius`\r\n\r\n## Triggers\r\n\r\nMultifactor authentication can be activated based on the following triggers:\r\n\r\n### Applications\r\nMFA can be triggered for a specific application registered inside the CAS service registry.\r\n\r\n```json\r\n\r\n{\r\n  \"@class\" : \"org.jasig.cas.services.RegexRegisteredService\",\r\n  \"serviceId\" : \"^(https|imaps)://.*\",\r\n  \"id\" : 100,\r\n  \"authenticationPolicy\" : {\r\n    \"@class\" : \"org.jasig.cas.services.DefaultRegisteredServiceAuthenticationPolicy\",\r\n    \"multifactorAuthenticationProviders\" : [ \"java.util.LinkedHashSet\", [ \"mfa-duo\" ] ],\r\n    \"failOpen\" : false\r\n  }\r\n}\r\n\r\n```\r\n\r\n### Principal Attribute\r\nMFA can be triggered for all users/subjects carrying a specific attribute that matches configured attribute value. The attribute\r\nvalue is a regex pattern and must match the authentication flow\r\nid of an available MFA provider described above. See below to learn about how to configure MFA settings. \r\n\r\n### Opt-In Request Parameter\r\nMFA can be triggered for a specific authentication request, provided\r\nthe initial request to the CAS `/login` endpoint contains a parameter\r\nthat indicates the required MFA authentication flow. The parameter name\r\nis configurable, but its value must match the authentication provider id\r\nof an available MFA provider described above. \r\n\r\n```\r\n\r\nhttps://.../cas/login?service=...&<PARAMETER_NAME>=<MFA_PROVIDER_ID>\r\n\r\n```\r\n\r\n### Principal Attribute Per Application\r\nAs a hybrid option, MFA can be triggered for a specific application registered inside the CAS service registry, provided\r\nthe authenticated principal carries an attribute that matches configured attribute value. The attribute\r\nvalue can be an arbitrary regex pattern. See below to learn about how to configure MFA settings.\r\n```json\r\n{\r\n  \"@class\" : \"org.jasig.cas.services.RegexRegisteredService\",\r\n  \"serviceId\" : \"^(https|imaps)://.*\",\r\n  \"id\" : 100,\r\n  \"authenticationPolicy\" : {\r\n    \"@class\" : \"org.jasig.cas.services.DefaultRegisteredServiceAuthenticationPolicy\",\r\n    \"multifactorAuthenticationProviders\" : [ \"java.util.LinkedHashSet\", [ \"mfa-duo\" ] ],\r\n    \"principalAttributeNameTrigger\" : \"memberOf\",\r\n    \"principalAttributeValueToMatch\" : \"faculty|allMfaMembers\"\r\n  }\r\n}\r\n\r\n```\r\n\r\n## Fail-Open vs Fail-Closed\r\nThe authentication policy by default supports fail-close mode, which means that if you attempt to exercise a particular\r\nprovider available to CAS and the provider is not available cannot be pinged, authentication will be stopped and an error\r\nwill be displayed. You can of course change this behavior so that authentication proceeds without exercising the provider\r\nfunctionality, if that provider cannot respond. \r\n\r\n## Ranking Providers\r\nAt times, CAS needs to determine the correct provider when step-up authentication is required. Consider for a moment that CAS\r\nalready has established an SSO session with/without a provider and has established a level of authentication. Another incoming\r\nrequest attempts to exercise that SSO session with a different and often competing authentication requirements that may differ\r\nfrom the authentication level CAS has already established. Concretely, examples may be:\r\n\r\n- CAS has achieved an SSO session, but a separate request now requires step-up authentication with DuoSecurity.\r\n- CAS has achieved an SSO session with an authentication level satisfied by DuoSecurity, but a separate request now requires step-up \r\nauthentication with YubiKey. \r\n\r\nIn certain scenarios, CAS will attempt to rank authentication levels and compare them with each other. If CAS already has achieved a level\r\nthat is higher than what the incoming request requires, no step-up authentication will be performed. If the opposite is true, CAS will\r\nroute the authentication flow to the required authentication level and upon success, will adjust the SSO session with the new higher \r\nauthentication level now satisfied. \r\n\r\nRanking of authentication methods is done per provider via specific properties for each in `cas.properties`.\r\n\r\n## Settings\r\nThe following general MFA settings are available for configuration in `cas.properties`:\r\n\r\n```properties\r\n# cas.mfa.principal.attribute=\r\n# cas.mfa.principal.attribute.value=\r\n# cas.mfa.request.parameter=\r\n```\r\n\r\n\r\n"},"comment":{"url":"https://api.github.com/repos/Jasig/cas/issues/comments/198827525","html_url":"https://github.com/Jasig/cas/pull/1496#issuecomment-198827525","issue_url":"https://api.github.com/repos/Jasig/cas/issues/1496","id":198827525,"user":{"login":"frett","id":47818,"avatar_url":"https://avatars.githubusercontent.com/u/47818?v=3","gravatar_id":"","url":"https://api.github.com/users/frett","html_url":"https://github.com/frett","followers_url":"https://api.github.com/users/frett/followers","following_url":"https://api.github.com/users/frett/following{/other_user}","gists_url":"https://api.github.com/users/frett/gists{/gist_id}","starred_url":"https://api.github.com/users/frett/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/frett/subscriptions","organizations_url":"https://api.github.com/users/frett/orgs","repos_url":"https://api.github.com/users/frett/repos","events_url":"https://api.github.com/users/frett/events{/privacy}","received_events_url":"https://api.github.com/users/frett/received_events","type":"User","site_admin":false},"created_at":"2016-03-20T02:08:15Z","updated_at":"2016-03-20T02:08:15Z","body":"all my testing looks good, I skimmed over the code one last time and made a few minor corrections, but other than that I think this is ready to get merged"}}