{"action":"created","issue":{"url":"https://api.github.com/repos/Jasig/cas/issues/1343","labels_url":"https://api.github.com/repos/Jasig/cas/issues/1343/labels{/name}","comments_url":"https://api.github.com/repos/Jasig/cas/issues/1343/comments","events_url":"https://api.github.com/repos/Jasig/cas/issues/1343/events","html_url":"https://github.com/Jasig/cas/pull/1343","id":121428417,"number":1343,"title":"Decouple authentication from CASImpl","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/Architecture","name":"Architecture","color":"5319e7"},{"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/New%20Feature","name":"New Feature","color":"207de5"}],"state":"open","locked":false,"assignee":null,"milestone":{"url":"https://api.github.com/repos/Jasig/cas/milestones/11","html_url":"https://github.com/Jasig/cas/milestones/4.2.0","labels_url":"https://api.github.com/repos/Jasig/cas/milestones/11/labels","id":1202350,"number":11,"title":"4.2.0","description":"CAS version 4.2.0 minor 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":6,"closed_issues":166,"state":"open","created_at":"2015-07-10T11:23:44Z","updated_at":"2015-12-18T05:56:38Z","due_on":"2015-12-25T05:00:00Z","closed_at":null},"comments":31,"created_at":"2015-12-10T08:24:01Z","updated_at":"2015-12-18T06:35:50Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/Jasig/cas/pulls/1343","html_url":"https://github.com/Jasig/cas/pull/1343","diff_url":"https://github.com/Jasig/cas/pull/1343.diff","patch_url":"https://github.com/Jasig/cas/pull/1343.patch"},"body":"Closes https://github.com/Jasig/cas/issues/1315\r\n\r\nThis pull introduces the following new concepts:\r\n\r\n1. `AuthenticationContext`: represents the final authentication event, collected from login flows and combined into one. The context will include a composite authentication object that represents a final view on all authentication attributes and principal attributes from all events, merged into a single entity. \r\n2. `AuthenticationContextBuilder`: builds `AuthenticationContext`. Responsible to collect authentication objects from flows, and builds the final context after reviewing all authentications. \r\n3. `AuthenticationSupervisor`: an abstraction that acts as a bridge between the authentication layer and upper layers (flows for example). All components interact with a supervisor.\r\n\r\nThe idea here is to lay the ground work for MFA functionality, based on the cas-MFA extension project. Presently, there exists only a single flow and one set of credentials but as we start to add subflows to MFA to handle secondary credentials and flows, this design is needed to keep collecting credentials and authentications from all flows, and at the very end, a single TGT is issued by CASImpl. Presently, CASImpl is tied to the authentication event, so every authN event potentially creates a new TGT which is not practical. \r\n\r\nExample snippet:\r\n\r\n```java\r\nthis.authenticationSupervisor.authenticate(credential);\r\n...\r\n...//There could be many other authenticate() calls for various types of credentials...\r\n...\r\nfinal AuthenticationContext authenticationContext = this.authenticationSupervisor.build();\r\nfinal TicketGrantingTicket tgt = this.centralAuthenticationService.createTicketGrantingTicket(authenticationContext);\r\n```\r\n\r\nA supervisor is constructed as such, acting as a bridge:\r\n\r\n```java\r\nprivate AuthenticationManager manager;\r\nprivate DefaultAuthenticationContextBuilder builder;\r\nprivate DefaultAuthenticationSupervisor authenticationSupervisor;\r\n\r\n@Before\r\npublic void setup() {\r\n    this.builder = new DefaultAuthenticationContextBuilder();\r\n    final DefaultPrincipalElectionStrategy principalStrategy = new DefaultPrincipalElectionStrategy();\r\n    principalStrategy.setPrincipalFactory(new DefaultPrincipalFactory());\r\n    builder.setPrincipalElectionStrategy(principalStrategy);\r\n\r\n    final AcceptUsersAuthenticationHandler handler = new AcceptUsersAuthenticationHandler();\r\n    handler.setUsers(Collections.singletonMap(\"casuser\", \"Mellon\"));\r\n    this.manager = new PolicyBasedAuthenticationManager(handler, new SimpleTestUsernamePasswordAuthenticationHandler());\r\n\r\n    this.authenticationSupervisor = new DefaultAuthenticationSupervisor();\r\n    this.authenticationSupervisor.setAuthenticationContextBuilder(this.builder);\r\n    this.authenticationSupervisor.setAuthenticationManager(this.manager);\r\n}\r\n```\r\n\r\nWhen the final `AuthenticationContext` is built, we need to examine all authentication objects (and their principals) from everything that is collected. Authentication attributes and principal attributes are all merged together, and the primary principal is selected out of the many authN events. By default, the first authentication is considered to be the primary authN, whose principal is the primary principal. "},"comment":{"url":"https://api.github.com/repos/Jasig/cas/issues/comments/165689694","html_url":"https://github.com/Jasig/cas/pull/1343#issuecomment-165689694","issue_url":"https://api.github.com/repos/Jasig/cas/issues/1343","id":165689694,"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},"created_at":"2015-12-18T06:35:50Z","updated_at":"2015-12-18T06:35:50Z","body":"Reviewed. It turns out that the authentication object contains everything we need to get it passed around. It's as \"lightweight\" as it can be for now. Also, I think if we were to create, let's say a lighter version of the Authentication object, we'd need to find a way to copy the contents of the real authentication into the light-weight version, still making sure that those copied items are serializable, which means possibly lots of transformations. That sounds like a lot of effort to me, compared to the energy it takes to figure out what in the real authentication object may cause serialization issues, and in what ways those can be solved. \r\n\r\nMakes sense? \r\n\r\nReviewing our implementations here, I am more and more convinced that everything we have right now is perfectly suited for SWF. All objects are meant to be serializable and perfectly are. What I was worried about was any \"external\" implementations by deployments, or weird implementations of a Principal by a deployment that violates this rule, but, now I that rethink about it, that is of no concern to us really. We don't ever expect folks to reimplement the Authentication object or the Principal, and if they do, they would need to follow the design guidelines in making sure their impls are safe and sound. So I think we should be good here.\r\n\r\n@leleuj let me know how you feel about this patch. "}}