External authenticator implementation (Issue #32)#98
External authenticator implementation (Issue #32)#98craigweston wants to merge 1 commit intorbCAS:masterfrom
Conversation
|
Thanks. I will look into this the coming days. |
|
The problem I see with the proposed solution is, that there is no way to connect an arbitrary CASino account with an external connector. Ideally, the user flow would be as follows:
That way the external authenticators would not depend on a specific normal authenticator. Thoughts? |
|
Thanks for looking at this. The username seems to be the common piece of information that could be used to connect the external authenticator to another CASino authenticator account. The external authenticator should map the "normal" authenticator's username to the external account specific identifier. Once logged in via the normal authenticator, this mapping could be setup by clicking a "connect" button on the sessions screen. It would then be up to the external authenticator to implement a function for handling this and creating the necessary mapping based on the currently logged in username. As an example, the Facebook authenticator maps Facebook ID to a username. Facebook specific data is returned via the extra attributes when logging in with Facebook, but it is the mapped username that is returned as the username in the user_data: There is also an option to return extra attributes from columns in the mapped user table (the "normal" authenticator). I'm not sure how this would work with something like LDAP, since the LDAP information is attained upon login and not stored in the database. Let me know your thoughts and whether you think this would be enough to link the accounts. |
|
Hi @pencil , Dose this PR in consideration, this seems to have very good feature, are you considering it to merge? |
|
Hi @craigweston , This branch has merge conflict, can you look in to it? |
|
@trkrameshkumar |
|
Any updates on this PR? I planned to make an external authenticator for WeChat. This PR might help a lot. |
I have implemented external authenticator support for CASino based on the description you provided on Issue 32:
My needs were specifically for Facebook authentication using their JavaScript SDK. I have created a Facebook authenticator to work with this external authentication implementation, which you can view here.
Configuration:
I have added a new section to the
cas.ymlfile which mimics the existing authenticator section.An example of this:
Implementation:
The external authenticators were designed with the expectation that each will provide a view and a validation function.
External authenticator base class:
View:
The view function provides the path to the view, used for rendering the button on the login page.
An example of this taken from my casino_facebook-authenticator:
Because the view is embedded in the external authenticator itself, it is expected that the external authenticators will be implemented as minimal Rails Engines.
Validation
Unlike the current validation function that relies on a username and password, I have made the external authenticator's validation function require request parameters and cookies. I figured this would provide the most flexibility while still providing the necessary data to support most authentication services.
As an example, my Facebook authenticator expects the access token to be generated on the client side and then passed via POST parameters to the server for server side verification. The assumption is that other external authenticators would use a similar client side approach for generating the necessary authentication tokens or cookies required.
Processor Concern - Authentication
In order to support this new validation functionality, I had to make changes to the app/processors/casino/processor_concern/authentication.rb.
There are now two different validation functions:
You'll notice that the
validate_external_credentialsonly validates for the authenticator that was submitted via theexternalparameter.The common functionality has been placed in the
validatefunction:Because there are now two different types of authenticators, I had to also change the
authenticatorsmethod signature to take an authenticator type. The cached@authenticatorshas also been changed to be a hash, which is keyed on authenticator type.Login Credential Acceptor Processor
The trigger that is used to know when to invoke an external authenticator or a regular authenticator happens based on whether the external parameter is submitted. This check happens in the /login_credential_acceptor_processor.rb.
Login Page
The external authenticator buttons are rendered on the login page within an inline list. Each view is wrapped in its own form, containing the login ticket and external hidden inputs.
The idea being that each authenticator will submit the wrapping form when necessary, including any additional data that may be needed on the server side.
As an example, my Facebook authenticator submits the form via JavaScript after the Facebook login process has completed and the access token has been added to the form dynamically as a hidden input.
External Authenticator List
Because the view needs to render a view for each of the authenticators, I pass a list of external authenticators to the view via the
@external_authenticators. This list is passed from the processor, to the listener and then to the view. This is not ideal, as it does introduce some repetitiveness in the processor, but I needed to be able to reuse the processor_concern/authentication.rb'sauthenticatorsmethod, and therefore keeping this call in the processor made sense.Example (login_credential_requestor_processor.rb):
Please let me know if you have any questions, concerns or changes. I look forward to hearing your input.
Thank you.