internet2 / shibboleth-multi-context-broker Goto Github PK
View Code? Open in Web Editor NEWShibboleth Multi-context Broker
Shibboleth Multi-context Broker
We configured the MCB latest distribution (1.2.5) into a Shibboleth IdP 2.4.4, along with the Duo plugin for it. We configured the initial context login page to be a JSP (login.jsp). Then we set up a test to force Duo authentication. The MCB gets control, sends the user to the login page correctly for initial authentication, but is then just giving control back to the IdP and not running the 2nd leg of authentication with Duo. With the exact same config and test, just changing the login page config to be the sample Velocity template for such, our test works as expected, going on to Duo after the login is completed. So a bug has been introduced at some point in the last few MCB releases that has broken support for a JSP-based login page. (Separately shared an idp-process log with Paul Hethmon illustrating the failure.)
When our metadata is read MCB throws the following exception due to a missing null pointer check.
16:28:03.842 - ERROR [edu.internet2.middleware.assurance.mcb.authn.provider.MCBLoginServlet:602] - Exception calling submodule.
java.lang.NullPointerException: null
at edu.internet2.middleware.assurance.mcb.authn.provider.ui.IDPUIHandler.getServiceLogo(IDPUIHandler.java:190) ~[IDPUIHandler.class:na]
at edu.internet2.middleware.assurance.mcb.authn.provider.MCBLoginServlet.doVelocity(MCBLoginServlet.java:692) [MCBLoginServlet.class:na]
at edu.uchicago.identity.mcb.authn.provider.duo.DuoLoginSubmodule.displayLogin(DuoLoginSubmodule.java:102) ~[DuoLoginSubmodule.class:2.1.0]
at edu.internet2.middleware.assurance.mcb.authn.provider.MCBLoginServlet.showMethods(MCBLoginServlet.java:594) [MCBLoginServlet.class:na]
at edu.internet2.middleware.assurance.mcb.authn.provider.MCBLoginServlet.service(MCBLoginServlet.java:138) [MCBLoginServlet.class:na]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:725) [servlet-api.jar:na]
Example UIInfo
<md:EntityDescriptor entityID="http://www.workday.com/fau3">
<md:SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
md:Extensionsmdui:UIInfo<mdui:DisplayName xml:lang="en">FAU Workday - fau3 - P3/mdui:DisplayName<mdui:Description xml:lang="en">Workday is designed to work the way we work today and enables nimble processes for the data driven organization. Log in to manage your, information, request time off, access pay stubs, purchases, and other related tasks. Users without an FAUNet ID may use the following link to login <a href="https://impl.workday.com/fau3/login.flex?redirect=n"">directly to Workday</a>. /mdui:Description<mdui:InformationURL xml:lang="en">http://www.workday.com/mdui:InformationURL<mdui:Logo width="159" height="62">https://images.workday.com/shared/wd-logo.gif/mdui:Logo/mdui:UIInfo/md:Extensions
md:KeyDescriptor
ds:KeyInfo
ds:X509Data
When using the JAAS login submodule with JSP pages, the page must be qualified with a leading slash. When it's not, the container cannot find the page and you end up with a 404 response.
I'm using version 1.2.1 of the MCB and if somebody directly accesses the login servlet, MCBLoginServlet.java, it raises an exception and code 500 is returned by Apache httpd. In IdP without MCB there is a possibility to check for a direct access and return a proper message without returning 500 status.
<%
StorageService storageService = HttpServletHelper.getStorageService(application);
LoginContext loginContext = HttpServletHelper.getLoginContext(storageService, application,request);
if (loginContext == null) {
%>
To fix this issue I added "try" block, line 130, in the "service" method of MCBLoginServlet class and that solved the problem.
try { application = this.getServletContext();
loginContext = (LoginContext)HttpServletHelper.getLoginContext(HttpServletHelper.getStorageService(application), application, request);
entityDescriptor = HttpServletHelper.getRelyingPartyMetadata(loginContext.getRelyingPartyId(),
HttpServletHelper.getRelyingPartyConfigurationManager(application));
entityID = entityDescriptor.getEntityID();
log.debug("Relying party = [{}]", entityID);
} catch (Exception e) {
log.error("Can't find entityID of the SP");
}
Is the original behavior intentional or is it an overlooked error?
I will try to reproduce locally. A remote user claims that she always gets an error hitting the IdP if and only if she uses IE11 with the Microsoft OneNote 2013 browser plug-in enabled.
Apr 29, 2014 5:54:49 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet MCBLoginServlet threw exception
java.lang.NullPointerException
at edu.internet2.middleware.assurance.mcb.authn.provider.MCBLoginServlet.service(MCBLoginServlet.java:127)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at edu.internet2.middleware.shibboleth.idp.util.NoCacheFilter.doFilter(NoCacheFilter.java:50)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at edu.internet2.middleware.shibboleth.idp.session.IdPSessionFilter.doFilter(IdPSessionFilter.java:87)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at edu.internet2.middleware.shibboleth.common.log.SLF4JMDCCleanupFilter.doFilter(SLF4JMDCCleanupFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
at org.apache.coyote.ajp.AjpAprProcessor.process(AjpAprProcessor.java:429)
at org.apache.coyote.ajp.AjpAprProtocol$AjpConnectionHandler.process(AjpAprProtocol.java:384)
at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1556)
at java.lang.Thread.run(Thread.java:745)
If a user has authenticated previously at a context level of "bronze", then the new SP requests either "silver" or "bronze" (in that specific order), the MCB will return "silver" even though the user has not completed that level of authentication.
The change/fix is to force upgraded authentication in this scenario. A new option "showSatisfiedContexts" was added to control the behavior of whether already satisfied contexts will be shown in the selection list. The default behavior is false, to not show already satisfied contexts/methods in the list. Only the other levels would be shown.
Shibboleth relying party configuration allows a default authentication method to be specified per relying party. Make use of the default value when a RP does not send a method (context) with their request.
Still outstanding is whether to use the default method when the RP does send a value. If so, does it get added to the beginning or the end of the list?
This issue here is just in case that this LoginHandler.AUTHENTICATION_INSTANT_KEY
request attribute is critical and needs to be passed back to the IDP's AuthenticationEngine
The idpui:displayName tag in the IDP's taglib support has more sources for an SP's display name than just the mdui element. This is useful when metadata contains a serviceName tag or you want to populate the element with the SP's hostname if no display name is set. Specifics here: https://wiki.shibboleth.net/confluence/display/SHIB2/IdPAuthUserPassLoginPage#IdPAuthUserPassLoginPage-ServiceProviderName
This would be a useful addition to the $uiName variable made available in Velocity.
If one sets in multi-context-broker.xml
-1
then instead of an "unlimited number of login failures" as indicated by the documentation the IdP will send the user back to the SP with a SAML error after the first login failure.
I believe this is because of this if() statement in MCBLoginServlet.java:
if (principal.getFailedCount() >= mcbConfig.getMaxFailures())
With maxFailures set to -1 that test will always be true after the first login failure.
Something like
if ((principal.getFailedCount() >= mcbConfig.getMaxFailures()) && (mcbConfig.getMaxFailures() != -1))
appears to fix the issue.
We have had reports from several users who are unable to login to our Shibboleth server after implementing the MCB plugin to the IdP. After severals days of troubleshooting, I lucked into the solution when one of our help desk staff (against policy!) added the user's password to their support ticket. The password has a space at the end, which is allowed by our password policy (it's actually a passphrase policy, which allows spaces). I replicated the conditions for this user by taking a test account and attempting to login with a passphrase that has no whitespace at either end and again after changing to a passphrase with a space character at the end. The second test failed, which led me to look at the source for both the IdP and the MCB.
The default behavior of the IdP is to pass the user's password as-is to the authentication source, but the MCB runs it through the DatatypeHelper.safeTrimOrNullString() method first, which strips whitespace off of the beginning or end of the password.
Luckily we are in the middle of the Summer, but as the Fall starts we will probably run into many more users with this issue.
Please remove the call to safeTrimOrNullString() so the MCB follows the identical behavior of the "normal" IdP code.
When the IDMS returns a context that is not configured in the MCB, it throws a NPE trying to resolve the context:
23:23:37.708 - TRACE [edu.internet2.middleware.assurance.mcb.authn.provider.MCBLoginServlet:562] - Looking up method for context name = [http://id.i
ncommon.org/assurance/bronze]
23:23:37.719 - ERROR [edu.internet2.middleware.assurance.mcb.authn.provider.MCBLoginServlet:346] - Exception calling submodule.
java.lang.NullPointerException: null
at edu.internet2.middleware.assurance.mcb.authn.provider.MCBLoginServlet.showMethods(MCBLoginServlet.java:563) [multi-context-broker-1.1.4.j
ar:na]
at edu.internet2.middleware.assurance.mcb.authn.provider.MCBLoginServlet.performAuthentication(MCBLoginServlet.java:266) [multi-context-brok
er-1.1.4.jar:na]
at edu.internet2.middleware.assurance.mcb.authn.provider.MCBLoginServlet.service(MCBLoginServlet.java:158) [multi-context-broker-1.1.4.jar:n
a]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717) [tomcat6-servlet-2.5-api-6.0.24.jar:na]
-------- Forwarded Message --------
Subject: MCB bug on failed logins?
Date: Tue, 28 Apr 2015 18:45:54 +0000
From: Ho, PeiQuan [email protected]
Reply-To: Shib Users [email protected]
To: Shib Users [email protected]
Hi,
I’m running some testing on the IDP with MCB. I noticed that when I’m directed to the IDP login page and I simply don’t login and just refresh the page, the MCB regards this as an SSO session and tries to query LDAP using a null user. This fails of course. But it also increments the failed login count. The odd thing is in the logs, it shows that there was actually no previous session found, but the MCB still thinks it is SSO. Is this the place to be reporting possible MCB bugs?
BTW, here’s what I see in the logs when I refresh the login page.
14:33:19.675 - INFO [Shibboleth-Access:73] - 20150428T183319Z|130.64.204.178|:443|/profile/SAML2/Redirect/SSO|
14:33:19.744 - DEBUG [edu.internet2.middleware.assurance.mcb.authn.provider.MCBLoginHandler:92] - MCBConfiguration bean = [edu.internet2.middleware.assurance.mcb.authn.provider.MCBConfiguration@67c04226]
14:33:19.745 - DEBUG [edu.internet2.middleware.assurance.mcb.authn.provider.MCBLoginHandler:106] - Relying party = []
14:33:19.745 - TRACE [edu.internet2.middleware.assurance.mcb.authn.provider.MCBLoginHandler:248] - No session found. Previous Session Support setting = [true]
14:33:19.745 - DEBUG [edu.internet2.middleware.assurance.mcb.authn.provider.MCBLoginHandler:280] - Redirecting to https:///idp/Authn/MCB
14:33:19.805 - TRACE [edu.internet2.middleware.assurance.mcb.authn.provider.MCBLoginServlet:119] - =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
14:33:19.805 - DEBUG [edu.internet2.middleware.assurance.mcb.authn.provider.MCBLoginServlet:120] - Request received from [130.64.204.178]
14:33:19.805 - DEBUG [edu.internet2.middleware.assurance.mcb.authn.provider.MCBLoginServlet:128] - principal = [{MCBUsernamePrincipal}[principal]]
14:33:19.806 - DEBUG [edu.internet2.middleware.assurance.mcb.authn.provider.MCBLoginServlet:137] - Relying party = []
14:33:19.806 - DEBUG [edu.internet2.middleware.assurance.mcb.authn.provider.MCBLoginServlet:170] - Performing authentication for request.
14:33:19.806 - DEBUG [edu.internet2.middleware.assurance.mcb.authn.provider.MCBLoginServlet:207] - Found 2nd leg of authentication, performing authentication.
14:33:19.807 - DEBUG [edu.internet2.middleware.assurance.mcb.authn.provider.MCBLoginServlet:806] - Getting requested contexts for relying party = []
14:33:19.807 - DEBUG [edu.internet2.middleware.assurance.mcb.authn.provider.JAASLoginSubmodule:244] - Attempting to authenticate user null
14:33:19.819 - TRACE [edu.vt.middleware.ldap.jaas.LdapLoginModule:144] - Begin initialize
.
.
.
Thanks,
-PQ
Submitting an empty form for the JAAS module results in a NPE.
Seems that the MCB is no longer in maven central (uchicago/mcb-duo#5) we need to get this pushed back up there to assist module developers.
See Steven Carmody's thread on shib-assure.
Subject: Re: [shib-assure] 1.2.2 testing -- good news and, possibly bad news?
Date: Fri, 13 Feb 2015 08:37:04 -0800
From: David Walker [email protected]
To: [email protected]
Keith,
Chiming in... I also remember discussion of this issue. I think the general principle is that the configured initial authentication context should be handled separate from the incoming request from the SP, making behavior for the first SP and the second SP the same (the second SP exhibiting the correct behavior here). I looked at our Github issue list, and I don't see this one there, however, so I'll add it.
...
David
On 02/12/2015 10:26 AM, Wessel, Keith wrote:
...
However, and I don’t know if this has been tackled yet, we still have the problem with the initial context being “good enough” and the MCB stopping there. To reiterate this issue:
Configure the IDP to have Password and Duo. Configure password as the only initial context since one can’t Duo auth until we know their principal.
With no session, go to an SP that accepts DUO then Password, in that order.
MCB prompts for password, user successfully authenticates.
Rather than giving the option of stepping up to Duo or even requiring it, user gets sent back to SP with Password.
If the SP described above is the 2nd SP the user visits in the session and the user already has satisfied Password from their 1st SP authentication, the MCB will allow for stepping up to Duo or possibly require it depending on configuration. It’s a different user experience, and it provides for functionality (stepping up) different than the 1st scenario above.
I recall agreeing that the scenario should be the same whether the session already existed or was newly created. It’s possible this was already fixed and I’m missing a configuration item. Can someone chime in here and help me out?
Keith
Might just be a special case of issue #3.
To reproduce:
Expected results:
Blank login form, no error.
Actual results:
Login form is shown, and actually works, but is preceded by ugly backtrace.
Problem appears to go away if I remove
#if ($loginFailed != "")
<p>$loginFailed</p>
#end
from templates/jaaslogin.vm.
java.lang.NullPointerException at edu.internet2.middleware.assurance.mcb.authn.provider.JAASLoginSubmodule$SimpleCallbackHandler.handle(JAASLoginSubmodule.java:313) at javax.security.auth.login.LoginContext$SecureCallbackHandler$1.run(LoginContext.java:947) at javax.security.auth.login.LoginContext$SecureCallbackHandler$1.run(LoginContext.java:944) at java.security.AccessController.doPrivileged(Native Method) at javax.security.auth.login.LoginContext$SecureCallbackHandler.handle(LoginContext.java:943) at edu.vt.middleware.ldap.jaas.AbstractLoginModule.getCredentials(AbstractLoginModule.java:429) at edu.vt.middleware.ldap.jaas.LdapLoginModule.login(LdapLoginModule.java:98) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at javax.security.auth.login.LoginContext.invoke(LoginContext.java:762) at javax.security.auth.login.LoginContext.access$000(LoginContext.java:203) at javax.security.auth.login.LoginContext$4.run(LoginContext.java:690) at javax.security.auth.login.LoginContext$4.run(LoginContext.java:688) at java.security.AccessController.doPrivileged(Native Method) at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:687) at javax.security.auth.login.LoginContext.login(LoginContext.java:595) at edu.internet2.middleware.assurance.mcb.authn.provider.JAASLoginSubmodule.authenticateUser(JAASLoginSubmodule.java:244) at edu.internet2.middleware.assurance.mcb.authn.provider.JAASLoginSubmodule.processLogin(JAASLoginSubmodule.java:168) at edu.internet2.middleware.assurance.mcb.authn.provider.MCBLoginServlet.performAuthentication(MCBLoginServlet.java:209) at edu.internet2.middleware.assurance.mcb.authn.provider.MCBLoginServlet.service(MCBLoginServlet.java:158) at javax.servlet.http.HttpServlet.service(HttpServlet.java:717) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at edu.internet2.middleware.shibboleth.idp.util.NoCacheFilter.doFilter(NoCacheFilter.java:50) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at edu.internet2.middleware.shibboleth.idp.session.IdPSessionFilter.doFilter(IdPSessionFilter.java:87) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at edu.internet2.middleware.shibboleth.common.log.SLF4JMDCCleanupFilter.doFilter(SLF4JMDCCleanupFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298) at org.apache.coyote.ajp.AjpAprProcessor.process(AjpAprProcessor.java:429) at org.apache.coyote.ajp.AjpAprProtocol$AjpConnectionHandler.process(AjpAprProtocol.java:384) at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1556) at java.lang.Thread.run(Thread.java:745)
The requestContext available to the ScriptedAttribute javascript normally contains the method "getInboundMessageTransport()", which can be used to retrieve the peer's IP address. This method does not appear to be mapped to the requestContext during attribute resolution when attribute resolution is handled by the MCB. The call to getInboundMessageTransport() always returns null
.
Example code:
logger.debug("Inbound transport peer address: {}", requestContext.getInboundMessageTransport().getPeerAddress());
When not using the MCB, the expected result is:
2015-05-27 13:45:58.939 - DEBUG [edu.internet2.middleware.shibboleth.resolver.Script.validAuthContexts:-1] - Inbound transport peer address: 10.9.2.5
When using the MCB, the actual result is:
2015-05-27 12:49:43.800 - ERROR [edu.internet2.middleware.shibboleth.common.attribute.resolver.provider.attributeDefinition.ScriptedAttributeDefinition:136] - 1D5EB29135FDC4F092D53E8C16B6CFDA - ScriptletAttributeDefinition validAuthContexts unable to execute script javax.script.ScriptException: sun.org.mozilla.javascript.internal.EcmaError: TypeError: Cannot call method "getPeerAddress" of null (<Unknown Source>#117) in <Unknown Source> at line number 117
We have an SP here which is sending forceAuth requests. The MCB seems to send the SP an authFail message rather than causing the login screen to be re-displayed.
Tested on 1.1.3, 1.1.4, and 1.2.3.
Using the $UILogo variable in the jaaslogin.vm template causes the following output in the generated HTML:
<img src="org.opensaml.samlext.saml2mdui.impl.LogoImpl@1d0a2dab" />
The jaaslogin.vm template looks like this:
<div class="column zero">
#if ($UILogo)
<img src="$UILogo" />
#end
<p><strong>
Login to
#if ($UIName)
$UIName
#else
$UIEntityID
#end
</strong>
</p>
#if ($UIDescription)
<p> $UIDescription </p>
#end
#if ($UIPrivacyURL)
<p><em><a href="$UIPrivacyURL" target="_blank">Privacy Notice</a></em></p>
#end
#if ($UIInfoURL)
<p><em><a href="$UIInfoURL" target="_blank">More Information</a></em></p>
#end
<br/>
</div>
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.