unicon / cas-mfa Goto Github PK
View Code? Open in Web Editor NEWCAS server overlay with support for multifactor authentication.
License: Apache License 2.0
CAS server overlay with support for multifactor authentication.
License: Apache License 2.0
Presently, if an RP does not specify an authn method the CAS protocol takes effect and continues as usual. While this works fine and is the expected behavior, we may also want to define a default opt-in authn method, so that CAS may always function in MFA mode.
I think this is regarding the display name feature merged today: when display name value contains comma, behaves badly. As in, would like to use a Lastname, Firstname style entry ("Moayyed, Misagh") but that doesn't work.
This should be the last change/issue to tackle before we close out this milestone.
The requirement is to merge the existing master branch with heroku and push upstream, so the code becomes demoable to a certain extent.
Also, tag the master at the end of this milestone to create a baseline, move master to a new branch and march forward :)
This is the in-the-guts part of supporting multiple different "authn_method"s (another issue tracks the routing to potentially multiple sub-flows part of the story).
The Authentication in the TGT should wrap or otherwise reflect the potentially multiple Authentications achieved in the single sign-on session. modeling as a Set of Strings representing the labels of fulfilled authentication methods as the value of an Authentication attribute is promising.
When CAS prompts for an additional authentication factor, besides the option of providing providing that factor, the end-user should also have the option to click a button or link indicating "That's not me!" -- telling CAS to log out and re-start the login flow giving them the opportunity to log in, first using username and password, as themselves.
This addresses the abandoned single sign-on session case where the walking-up-user attempts to log in to something that requires an additional authentication factor and finds themselves prompted to add an authentication factor to someone else's single sign-on session.
ServletRequest-specific behavior should be in the ArgumentExtractor, the architectural component that's about extracting from servlet requests, rather than in the MfaService domain object itself.
The present functionality only allows to configure one authn method retriever, while in fact several may be active to retrieve data. This issue only addresses the concern from an architectural POV, where we need to refactor a number of components to allow a "list" of retrievers take effect and figure out the authn method, rather than just one. We'll still be assuming, for this issue only, that only one of these retrievers in the list can just produce data and the desired method, but nonetheless, the code should be looping through a list of configurable retrievers to find the authn method.
Summary: Getting one-time password wrong yields CAS is Unavailable screen.
Affected code: current Master branch
Steps to reproduce:
What should have happened:
Sensible error message included in a re-render of the one-time password prompt, with an opportunity to try again at providing a correct one-time password.
79ec6b7 backed out login JSP EL usage that only works under Tomcat 7 but not under Tomcat 6 (whereas Tomcat 6 support remains required).
Institute behavior at the Java / web flow layer to digest the required authentication method, if any, and make it available as a simple pre-digested requiredAuthenticationMethod
String (conversation scoped?) that the JSP can condition on. null
if no particular method required; the String identifier for the required method if one is required.
To incorporate the newest features introduced in 1.0-M2
When we resolve principal attributes, and are in the process of figuring out the attribute value that would specify the mfa, we need to provide a pluggable API so that an adopter would be able to manipulate the attribute value, to the right subflow.
So an institution might have an attribute value for mfa that is "very_strong", but that would need be translated at the CAS level to be "really_strong". By default we are going to assume attribute values do match and will have a no-op translator, but we should have the API that attempts to do so, just to be nice :)
When /cas/login
has an authn_method
parameter with an unrecognized value, CAS should present a suitable end-user-facing error experience, since CAS will be unable to walk the user through fulfilling the not-understood authentication method requirement and so cannot issue an ST suitable for the requesting service.
(Current behavior is to ignore the authn_method
which vends the user an ST that CAS expects will not be sufficient for login to the requesting service.)
Review the configuration and ensure the method is passed onto the response. Demonstrate perhaps via explicit log messages. Evergreen is to review setup and confirm whether method is missing from the final response.
It needs to describe where duo view files are, and how they are tied into the CAS config.
Presently, all authentication methods are created equal. These are simply tokens, that CAS would remember as what's been fulfilled during the authentication context.
More, we currently are assuming that while authentication methods can be specified via multiple channels (params, SvcReg, Attr), these channels cannot all at the same time indicate the mfa requirement. In order to support multiple means of conveying MFA triggers, and have them all produce possible values and play nice with each other at the same time, we need to come up with methods of how each authentication ranks and compares against another.
Use case might be, that:
So:
The engine needs to be smart enough to know that:
Some more background info:
In casMfaLoginView.jsp
<spring:message
code="service.mfa.service.mfa.inprogress.message"
arguments="${service.authenticationMethod},${service}" />
will include the raw value of the service
parameter in the JSP. The Adversary might place a markup snippet in the service URL parameter in an attempt to inject JavaScript, as in
https://localhost:/cas/login?authn_method=strong_two_factor&service=http://www.unicon.net"><script>alert('SECURITYALERT!!!')</script>
and this JSP will include that JavaScript in the page content delivered to the browser.
This is a potential SSO session stealing exploit.
This is an existing bug that I found out during testing:
I have an SSO session already that was backed by an MFA authn method. I then submit the following request to cas:
/cas/login?authn_method=some_valid_id&service=https://myservice&renew=true
Per protocol, I expect to see the login screen. I do not.
We are having problems trying to build with Maven. Am I missing something ? The source code is about 6 months old.
Thank you
cas-mfa-java/src/main/java/net/unicon/cas/mfa/MultiFactorAuthenticationProtocolValidationSpecification.java:34:83: Expected @param tag for 'validateProxyAuthenticationRequests'.
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] CAS Multifactor Authentication .................... SUCCESS [ 1.354 s]
[INFO] CAS MFA Core ...................................... FAILURE [ 4.845 s]
[INFO] CAS MFA Web Application ........................... SKIPPED
[INFO] CAS MFA Overlay ................................... SKIPPED
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
The current MFA solution only supports JIT selection of authn methods, via request parameters sent by the relying party (CAS client). We would also want to support the retrieval of the authn method via user attributes. The flow would be as such:
When credentials are submitted and user has authenticated, a principal is formed with a collection of user attributes. Via the configuration, provide a way for the adopter to specify which attribute value should be examined for the authentication method specified for the user. Based on the value, re-route the login flow.
If the attribute value is blank, ignore the MFA requirement and proceed normally. do not disable MFA, but simply comply with what may have been specified through other means and channels.
If the attribute value matches a flow id that CAS does not support, be sure to prompt and halt the login flow. Do not error out or crash, but simply explain the situation to the user via a friendly error message.
User attributes always take precedence over service registry settings or request parameters. Selection order for MFA requirements is always, user attribute first, then svc registry, then request parameters.
Accompany the PR with test cases and documentation as needed
The constructed authentication object that is placed into the final MFA-enabled TGT needs to not depend on a particular authentication object in the chain, but rather, should wrap the entire chain inside it.
This is to support the usecase of remembering and fulfilling all authentication methods (which there may be multiples of) on validation responses.
How can we be sure that the desired serviceValidateController
definition is controlling, and the non-mfa-aware implementation doesn't take effect instead?
We are currently assuming that the user attribute, which indicates the required MFA context is a single valued attribute. In reality, this may contain a list/set of attribute values. We'll need to support those cases as well.
In the event that more than one value is specified, we'll need to plug the set into the ranking engine to figure out which is the appropriate method to use.
Note that this is simply kept here for recording keeping and documentation. We dont plan to address this for the time being.
This issue is almost certainly a duplicate of details of other issues, is implied by other in-flight work.
Nonetheless, logging it as a very specific issue because raised at 2013-08-07 status call and impinges upon how Evergreen seeking to exercise code, so this issue will allow explicitly tracking resolution of this detail.
Where a specific authentication method is required, CAS first requires the basic username-and-password login. The result of that basic login is CAS knows about an authenticated Principal.
Here's the punchline: sub-flows modeling particular authentication methods need to be aware of, reflect, and enforce that the additional authentication they are obtaining authenticates that same Principal.
Logging in as Andrew in the main flow and then successfully presenting Misagh's one-time-password isn't evidence for a more strongly authenticated Andrew.
Likewise, the user shouldn't have to type their username again in the sub-flow's prompt for additional credential when CAS is already aware of who the user is supposed to be.
For a request to (chrome)
view-source:https://localhost:8443/cas/serviceValidate?service=http://www.unicon.net&ticket=ST-12-mYUbtWrLGiF5P4dVDL5p-cas.example.org&authn_method=strong_two_factor
I get
<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
<cas:authenticationSuccess>
<cas:user>casuser</cas:user>
</cas:authenticationSuccess>
</cas:serviceResponse>
Whereas the response should have included the authentication method.
We are keeping track of authn method and authn method source separate. Lets create an abstraction that holds both.
Given the insight at https://github.com/Unicon/cas-mfa/wiki/Modified-CAS-protocol that this project is about authentication method more so than about "LOA", rename away from talking about LOA in the code and instead talking about authentication method.
/cas/samlValidate
must enforce a required authn_method
if one is expressed by the ticket-validating relying party, but does not currently so enforce.
Currently, the webflow branching logic will always navigate to the mfa
state, regardless of the requested authentication method. While the build supports having multiple methods in place, a global redirection to one mfa state makes it difficult to handle another scheme of authentication handlers for a newly configured authn method.
The thought is to, instead of mapping the flow to one mfa
event, map the mfa branching to a state that is tied to the authentication method. The map would be based off of the authentication method string, such that for instance the flow would be able to switch to mfa_strong_two_factor
instead of just mfa
.
Demonstrate functionality, by having at least another authn method in the config.
differences in cas-mfa-web/src/main/webapp/WEB-INF/login-webflow.xml that don't seem related to mfa. Specifically, items related to lppe in the cas 3.5.2 baseline file are missing from cas-mfa-web/src/main/webapp/WEB-INF/login-webflow.xml.
To be consistent with the versioning scheme already established i.e. there already exists v1.0.0-M1
tag/version. So let's adopt this scheme going forward and march towards 1.0.0-M2
. @mmoayyed any objections?
So, since we have now the great RegisteredServiceAttributeMultiFactorAuthenticationArgumentExtractor.java
, lets do the same with the MultifactorArgumentExtractor class and rename it so it makes more sense as to what it really does. It serves us fine when we only had to support request parameters, but now that we are adding more, we should clarify the intention of the class.
Document what it takes to add MFA to an existing overlay project.
Currently, the validation logic only and simply compares authn methods and in case of a mismatch, forces reauthenticaton. This should not be the case with the new ranking algorithm in place. Validation should take into account the current method's rank, as well as the rank of what's requested, do a comparison and let the higher rank win. if the result of that comparison requires a re-authentication, then so be it. otherwise, no prompt and proceed normally.
What should be returned back to the application, is "what they requested" and not "what CAS has fulfilled". If app requests A, and CAS has fulfilled Y, and Y > A, then CAS should simply just not prompt and let the app know that A has been fulfilled.
Messages that are intended for customization should really come from message bundles:
<div id="msg" class="info">
<h2>Multifactor Authentication In Progress</h2>
<h4>Authentication method is set to [${service.authenticationMethod}].</h4>
<h4>Authentication is requested by [${service}].</h4>
</div>
and...
<div id="msg" class="info">
<h2>This service requires a specific authentication method in addition to username and password.</h2>
<strong>The additional required authentication method is [${requiredAuthenticationMethod}].
After successfully providing username and password, you will be prompted for this additional authentication
factor.</strong>
</div>
There may be other instances.
The user potentially will have fulfilled multiple rather than just one required authentication method. This should be communicated in the ticket validation response, perhaps with multiple <cas:authn_method>password</cas:authn_method>
elements.
The documentation will live close to the code (in its own docs
directory at the project root).
Clearly license as Apache 2 identical to Apereo CAS license as per Evergreen RFP terms.
Pull request offered addressing: #13
Just for record keeping: CAS4.1 is now available. While the current codebase is functional based on CAS 3.5.x, we should nonetheless at some point take the effort to upgrade the overlay to v4 and figure out what we can drop, etc.
Tagged as icebox for now.
When using org.jasig.cas.services.JpaServiceRegistryDaoImpl
for the serviceRegistryDao
bean, entries created via the services manager web application are not persisting to the underlying database. I'm wondering if there is a @transactional annotation missing somewhere?
I have used the following configuration with cas-mfa (replacing <cas:json-services-registry/>
in cas-mfa-web/src/main/webapp/WEB-INF/deployerConfigContext.xml
with the following:
<bean id="serviceRegistryDao" class="org.jasig.cas.services.JpaServiceRegistryDaoImpl"
p:entityManagerFactory-ref="entityManagerFactory" />
<!-- This is the EntityManagerFactory configuration for Hibernate -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true"/>
<property name="showSql" value="true" />
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean
id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://myhost.edu:3306/cas_mfa?autoReconnect=true"
p:password="password"
p:username="user" />
When I attempt to add an entry in the services manager UI, I get the following log entries, and find that no row has been inserted in the RegisteredServiceImpl table:
2013-09-03 17:02:50,303 DEBUG [org.jasig.cas.services.web.RegisteredServiceSimpleFormController] - <Removing form session attribute [org.jasig.cas.services.web.RegisteredServiceSimpleFormController.FORM.registeredService]>
2013-09-03 17:02:50,311 DEBUG [org.jasig.cas.services.web.RegisteredServiceSimpleFormController] - <No errors -> processing submit>
2013-09-03 17:02:50,312 DEBUG [org.hibernate.internal.SessionImpl] - <Opened session at timestamp: 13782529703>
2013-09-03 17:02:50,312 TRACE [org.hibernate.internal.SessionImpl] - <Setting flush mode to: AUTO>
2013-09-03 17:02:50,312 TRACE [org.hibernate.internal.SessionImpl] - <Setting cache mode to: NORMAL>
2013-09-03 17:02:50,317 TRACE [org.hibernate.engine.spi.IdentifierValue] - <ID unsaved-value: -1>
2013-09-03 17:02:50,317 TRACE [org.hibernate.event.internal.AbstractSaveEventListener] - <Transient instance of: org.jasig.cas.services.Registered
ServiceImpl>
2013-09-03 17:02:50,318 TRACE [org.hibernate.event.internal.DefaultMergeEventListener] - <Merging transient instance>
2013-09-03 17:02:50,328 TRACE [org.hibernate.event.internal.AbstractSaveEventListener] - <Saving [org.jasig.cas.services.RegisteredServiceImpl#<null>]>
2013-09-03 17:02:50,339 TRACE [org.hibernate.event.internal.WrapVisitor] - <Wrapped collection in role: org.jasig.cas.services.AbstractRegisteredService.allowedAttributes>
2013-09-03 17:02:50,340 TRACE [org.hibernate.engine.spi.ActionQueue] - <Adding an EntityIdentityInsertAction for [org.jasig.cas.services.RegisteredServiceImpl] object>
2013-09-03 17:02:50,342 TRACE [org.hibernate.engine.spi.ActionQueue] - <Adding insert with no non-nullable, transient entities: [EntityIdentityInsertAction[org.jasig.cas.services.RegisteredServiceImpl#<delayed:0>]]>
2013-09-03 17:02:50,342 TRACE [org.hibernate.engine.spi.ActionQueue] - <Adding resolved non-early insert action.>
2013-09-03 17:02:50,346 TRACE [org.hibernate.action.internal.UnresolvedEntityInsertActions] - <No unresolved entity inserts that depended on [[org.jasig.cas.services.RegisteredServiceImpl#<delayed:0>]]>
2013-09-03 17:02:50,347 TRACE [org.hibernate.action.internal.UnresolvedEntityInsertActions] - <No entity insert actions have non-nullable, transient entity dependencies.>
2013-09-03 17:02:50,348 TRACE [org.hibernate.internal.SessionImpl] - <Closing session>
2013-09-03 17:02:50,348 TRACE [org.hibernate.engine.jdbc.internal.LogicalConnectionImpl] - <Closing logical connection>
2013-09-03 17:02:50,348 TRACE [org.hibernate.engine.jdbc.internal.JdbcResourceRegistryImpl] - <Closing JDBC container [org.hibernate.engine.jdbc.internal.JdbcResourceRegistryImpl@2b0fe524]>
2013-09-03 17:02:50,348 TRACE [org.hibernate.engine.jdbc.internal.LogicalConnectionImpl] - <Logical connection closed>
2013-09-03 17:02:50,349 INFO [org.jasig.cas.services.web.RegisteredServiceSimpleFormController] - <Saved changes to service -1>
Using the exact same configuration with stock CAS 3.5.2 works correctly (that is, adding an entry persists to RegisteredServiceImpl).
Any ideas?
Demonstrate greeting the user by a user attribute on the additional authentication factor prompt JSPs.
Principal attributes should be available to these JSPs and it should be clear to CAS extension adopters how to customize the JSP page to greet the user by the institution's user attribute(s) of choice.
As in, "Welcome back, Misagh! (this isn't me!)"
(The "This isn't me" part is tracked in another Issue; this issue tracks the greeting by deployer-selected user attributes part of the story.)
The current MFA solution only supports JIT selection of authn methods, via request parameters sent by the relying party (CAS client). With support of the JSON service registry, ensure that each service definition can also specify a desired authentication method.
The existing argument extractor should be kept. If a service definition in the registry specifies an authentication method, use that exclusively, and ignore what's provided as the request parameter. If the service does not specify anything, look at the request parameter. The service registry definitions always take precedence.
Provide sufficient test cases to demonstrate the behavior. Also, update the documentation to explain the new behavior with examples, code snippets, etc.
/cas/proxyValidate
must enforce a required authn_method
if one is expressed by the ticket-validating relying party, but does not currently so enforce.
It is common for CAS clients to validate service tickets against `/cas/proxyValidate'
The case of actual proxy tickets is kind of interesting -- validation should traverse back to the underlying TGT to verify that the required authn_method
was fulfilled.
With the MFA extension, CAS returns the casServiceFailureView view to clients calling serviceValidate, despite the fact that the actual validation is successful. This problem began when a new service was added that has very long service URL. The symptom only presents on the second or subsequent ST validation after TGT creation. Reverting back to a non-MFA CAS demonstrates that the problem only occurs in MFA CAS. The symptoms do not occur only on requests with these very long service URL, rather, the service with very long URL puts CAS in a state where this happens with all services and a CAS restart is required to correct it. Additionally, a single instance of the very long URL will not necessarily trigger the problem. We added a few logger.debug lines to MultiFactorServiceValidateController.java and started getting a bit more info about where the problem was occurring:
2014-01-23 11:10:26,703 DEBUG [net.unicon.cas.mfa.web.MultiFactorServiceValidateController] - <ServiceTicket [ST-117-DLSkRVYvyer9tiTuEvqt-cas01.example.org] does not satisfy validation specification.>
2014-01-23 11:10:26,703 DEBUG [net.unicon.cas.mfa.web.MultiFactorServiceValidateController] - <convertedDescription is ticket ''{0}'' not recognizedand code is INVALID_TICKET>
From MultiFactorServiceValidateController.java:
if (!validationSpecification.isSatisfiedBy(assertion)) {
logger.debug("ServiceTicket [" + serviceTicketId + "] does not satisfy validation specification.");
return generateErrorView("INVALID_TICKET", "INVALID_TICKET_SPEC", null);
I may be able to correct or provide more info but I need a little assistance in where to start looking.
For the most part, all a deployer cares about in the args extractor config file, is the bean supportedAuthenticationMethodsConfig
. This is a mapping of methods->ranks.
Lets try and see if we can come up with a strategy to move this configuration outside the overlay and have CAS reference it, either as a cas.property or another config file. This will make it easier to add/remove methods, and will also simplify overlays because they no longer wold need the xml config file
Duo provides all configuration pieces for the handler (secret, client key, etc) but there is no such thing as application key. Clarify in the documentation what that is and how it can be obtained.
While greeting the user is desirable and affording the user the opportunity that they are not the currently logged in user identified by CAS is important (tracked in other Issues), the principal identifier should not be experienced as part of the form itself prompting for the additional authentication factor.
Succeeding or failing at presenting an additional authentication factor should generate entries in the CAS server audit trail log.
Successful and failed ticket validation attempts should generate audit trail log entries that reflect whether and what authentication method was fulfilled.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.