uPortal CVE-2014-5059 Workaround
In which I share instructions on how to fix your uPortal security.properties
to immediately block the CVE-2014-5059
vulnerability.
Structure of this blog post
This blog post provides:
- Why you should care
- How to determine if your uPortal deployment is affected
- How to compose a fix for your
security.properties
, and - How to apply the security.properties fix
This blog post is intended to be mechanically about fixing your portal. Given that there's this vulnerability, how do you quickly ascertain whether your portal is affected and fix it if you are.
I've resisted the urge to discuss how the vulnerability works, how the fix works, how Spring Security can help, and larger philosophical discussion. Those will be important conversations, but what I'm trying to communicate right here is just the facts on how you secure your portal.
Why you should care
CVE-2014-5059
is a nasty uPortal vulnerability whereby in certain configurations including the default out-of-the-box configuration, logging in users could log in as users other than themselves.
You should probably figure out if your uPortal is affected and, if affected, apply the workaround right now.
All uPortal versions are in principle vulnerable. Whether they're vulnerable in practice depends upon some specifics of how SecurityContext
s in use interact with the framework security APIs. All uPortal versions should apply the workaround discussed herein.
uPortal 4.0.15
and 4.1.1
ship with a fix to block this vulnerability by making the involved SecurityContext
class more careful. uPortal adopters should upgrade to those fixed uPortal versions or otherwise incorporate the code fix into their local uPortal environments. The code fix blocks the vulnerability for the affected SecurityContext
that ships in uPortal, regardless of your security.properties
configuration.
However. It is also possible to block this vulnerability through an adjustment to your security.properties
configuration, even before you update any Java code. You should probably do that right now. This blog post tells you how. (uPortal 4.0.15
and 4.1.1
also ship with fixed default and example security.properties
configurations.)
How to determine if your uPortal deployment is affected
Among the SecurityContext
implementations shipping in modern uPortal, only the CasAssertionSecurityContext
and its derivatives are vulnerable, and only in some (alas, typical) security.properties
configurations.
You are affected by this vulnerability if
- You are using the
CasAssertionSecurityContext
or its subclass,PasswordCachingCasAssertionSecurityContext
, AND - Your
security.properties
is configured such that aprincipalName
is declared on that context or on a parent context, AND - You are using uPortal prior to uPortal 4.0.15 / 4.1.1, since those versions fix this Context.
So, this security.properties
configuration would be affected
root=org.jasig.portal.security.provider.UnionSecurityContextFactory
root.cas=org.jasig.portal.security.provider.cas.CasAssertionSecurityContextFactory
root.simple=org.jasig.portal.security.provider.SimpleSecurityContextFactory
principalToken.root=userName
credentialToken.root=password
credentialToken.root.cas=ticket
. It would be affected because it declares the CasAssertionSecurityContext
AND it declares a non-blank principalToken
AND that principalToken
applies to the CasAssertionSecurityContext
(through inheritance down from root
to root.cas
).
and that is, alas, the default configuration shipping in uPortal prior to the fixed releases.
This configuration is also vulnerable
root=org.jasig.portal.security.provider.UnionSecurityContextFactory
root.cas=org.jasig.portal.security.provider.cas.PasswordCachingCasAssertionSecurityContextFactory
root.simple=org.jasig.portal.security.provider.SimpleSecurityContextFactory
principalToken.root=userName
credentialToken.root=password
credentialToken.root.cas=ticket
because it is using the also-affected PasswordCachingCasAssertionSecurityContext
which is a sub-class of CasAssertionSecurityContext
and so inherits the same bug.
You might be affected by this vulnerability if you are using a custom-developed uPortal SecurityContext AND your security.properties declares a principalName
on that context or on a parent context.
So, this security.properties
configuration might be affected:
root=org.jasig.portal.security.provider.UnionSecurityContextFactory
root.custom=edu.miskatonic.portal.TentacledSecurityContextFactory
root.simple=org.jasig.portal.security.provider.SimpleSecurityContextFactory
principalToken.root=userName
credentialToken.root=password
credentialToken.root.custom=symbol
Your portal might be affected by this vulnerability if you are using older CAS SecurityContexts or other SecurityContext implementations AND your security.properties
declares a principalName
on that context or on a parent context.
You are not affected by this vulnerability if you are exclusively using these security contexts
CacheLdapSecurityContext
(needs principalName and uses it properly)JAASSecurityContext
(does not need principalName, but copes properly if presented)RemoteUserSecurityContext
(does not need principalName, but copes properly if presented)SimpleLdapSecurityContext
(needs principalName and uses it properly)SimpleSecurityContext
(needs principalName and uses it properly)UnionSecurityContext
even if you are setting the principalName
on those contexts, because in some cases they actually need the principalName
token to know what user identity they should try to authenticate, and in the rest of the cases they happen to use the uPortal security APIs in a way to avoid this vulnerability.
The TrustSecurityContext
isn't interestingly prey to this vulnerability because its behavior is to accept whatever user identity without verifying the identity in any way -- non-demo environments using it are very suspect regardless of this vulnerability.
How to compose a fix for your security.properties
If your portal is affected by this vulnerability, the good news is there's a trivial change to your security.properties
you can make to block this vulnerability immediately.
The fix amounts to don't feed principalName
to Contexts that don't need and expect it, and especially don't feed principalName
to security Contexts that integrate with CAS.
The bad news is that the details of your security.properties
depend on details of your local authentication integration choices. Still, your security.properties
probably follows one of these patterns.
This section walks through some examples of security.properties
for different scenarios and discusses for each whether the configuration is vulnerable and how to change it to no longer be vulnerable. The way you are intended to use this section is to find the example that matches yours and apply it.
Setting the principalName only appropriately
For a configuration that is exclusively doing username and password authentication against the uPortal-internal user store
root=org.jasig.portal.security.provider.SimpleSecurityContextFactory
principalToken.root=userName
credentialToken.root=password
no change is required -- that security context needs and expects principalName
.
Likewise a configuration that is exclusively using LDAP authentication
root=org.jasig.portal.security.provider.SimpleLdapSecurityContextFactory
principalToken.root=userName
credentialToken.root=password
is not vulnerable and requires no change.
Likewise a configuration that is exclusively using REMOTE_USER authentication (in order to rely on a fronting Shibboleth SP, for example)
root=org.jasig.portal.security.provider.RemoteUserSecurityContextFactory
principalToken.root=remote_user
credentialToken.root=password
is not vulnerable and requires no change.
(The RemoteUserSecurityContext
doesn't actually need that remote_user
principalToken
and would work fine if it were principalToken.root=
-- the point here is that the RemoteUserSecurityContext
implementation takes pains to handle the case where the uid it is trying to store into the session doesn't stick due to a different one having been previously bound. It's still a good idea not to feed this context a principalName
token value it doesn't need.)
Not setting the principalName
For a configuration that is not setting principalName at all
## This is the factory that supplies the concrete authentication class
root=org.jasig.portal.security.provider.cas.CasAssertionSecurityContextFactory
principalToken.root=
credentialToken.root=ticket
no change is required - this configuration does not bind a request parameter as the username because the principalToken
is blank.
Setting the principalName on a context that does not need it
This configuration is one character different from the previous one
## This is the factory that supplies the concrete authentication class
root=org.jasig.portal.security.provider.cas.CasAssertionSecurityContextFactory
principalToken.root=u
credentialToken.root=ticket
and that one character is all it takes to be vulnerable. Do you see it? It's telling the portal that the parameter u
should be considered the principalToken
for the root
context which, here, is the CasAssertionSecurityContext
, but that security context doesn't need a principalToken
, and, in fact, is exactly the context that gets confused when you give it one.
This configuration is problematic in the same way:
## This is the factory that supplies the concrete authentication class
root=org.jasig.portal.security.provider.cas.CasAssertionSecurityContextFactory
principalToken.root=userName
credentialToken.root=ticket
except the principalName value here is the more plausible userName
instead of just u
.
The solution is to make the principalToken
blank
## This is the factory that supplies the concrete authentication class
root=org.jasig.portal.security.provider.cas.CasAssertionSecurityContextFactory
principalToken.root=
credentialToken.root=ticket
This tells the portal that no request parameter ought to be bound as the principal on the CasAssertionSercurityContext
, which is a good thing to tell the portal because that context doesn't need and prior to uPortal 4.0.15
/ 4.1.1
doesn't properly cope with the parameter when it's set.
Setting the principalName on a parent context of some contexts that need it and some that do not
This is the configuration that was default in uPortal up to this point. There's a parent Union
context that combines two child contexts, one that uses CAS and one that uses the simple security context to do username and password validation against uPortal's internal user store. This configuration was common because even in environments externalizing real user logins to CAS, the portal often retains some non-human portal template and administrative user accounts that it locally manages, and this configuration allows authenticating in either way.
root=org.jasig.portal.security.provider.UnionSecurityContextFactory
root.cas=org.jasig.portal.security.provider.cas.CasAssertionSecurityContextFactory
root.simple=org.jasig.portal.security.provider.SimpleSecurityContextFactory
principalToken.root=userName
credentialToken.root=password
credentialToken.root.cas=ticket
What's wrong with this configuration is that the principalToken
value is applied to the root
, and then the CAS context , as root.cas
, inherits it. The way to fix it is to specify the blank token at root
and then specify the userName
value only on the specific context that needs it, root.simple
. So you end up with:
root=org.jasig.portal.security.provider.UnionSecurityContextFactory
root.cas=org.jasig.portal.security.provider.cas.CasAssertionSecurityContextFactory
root.simple=org.jasig.portal.security.provider.SimpleSecurityContextFactory
principalToken.root=
credentialToken.root=
principalToken.root.simple=userName
principalToken.root.simple=password
credentialToken.root.cas=ticket
and this way root.cas
doesn't inherit a principalToken
value.
The general case
In general, here's how security.properties
works relevant to this issue.
-
You declare Security context factories that build SecurityContext instances.
-
Those factories are named, and their naming makes up a potential hierarchy of instances that get wired up to model the authentication of any given user. So,
root
is the parent ofroot.simple
androot.cas
. -
The configuration flows down the hierarchy, so if you set a
principalToken
at a node, it applies to the children of that node. -
You really don't want
principalToken
s applying to contexts that don't expect and understand them. -
Therefore in general move the configuration down the tree to the leaves so it's applying tightly just to the specific context that expects it. Do not apply any non-blank configuration to parent nodes in the tree. So,
principalToken.root.simple=userName
, notprincipalToken.root=userName
-
However, alas, you have to declare the property name even though it will have a blank value, so
principalToken.root=
.
Something else? Get help.
Is your security.properties
different from these examples such that you're not sure whether you're vulnerable or what needs done to fix it? Get help!
If you have a commercial support provider for your uPortal implementation, you might contact them for help.
Regardless of whether you have a commercial support provider, you can also get help on the uPortal email lists. Isn't open source great? Since this will be a discussion about using uPortal rather than a discussion of developing changes for inclusion in the uPortal product, it is most appropriately undertaken on the uportal-user@ email list.
How to apply the security.properties fix
This is, mechanically, how to apply a security.properties
fix. What content change you ought to make to your security.properties
is discussed above.
A. Fixing your uPortal as deployed
Modifying your deployed uPortal before fixing your source code, re-building, and re-deploying might or might not be the right move for you to make. Only you can decide how to wrangle your uPortal deployment.
A.0. Make a backup of your deployed security.properties
You always save a copy of a file you're about to edit live in a deployed environment, right?
A.1. Fix your security.properties
The file is WEB-INF/classes/properties/security.properties
in your deployed uPortal web application, which is probably a directory named uPortal
in the webapps
directory of your Tomcat servlet container.
Apply the change to no longer bind a principalName
to security contexts that should not have a principalName
bound onto them, as discussed above.
A.2. Restart Tomcat
Restart your servlet container to make uPortal re-load security.properties
and apply the new configuration.
B. Fixing your source code
Whether or not you fix in place, you should also fix your source code so on future builds and deploys you keep the fix.
B.1. Fix your security.properties
The security.properties
is in
/uportal-war/src/main/resources/properties/
in your source code.
What change you need to make to fix it is discussed thoroughly above.
B.2. Build
Build your changed portal however you normally build it. That might be mvn package
or maybe you combine building and deploying in your deploy step (the next step!)
B.3. Deploy
You probably stop Tomcat before you do this.
Deploy your changed portal however you normally do that. That might be ant deploy-war
.
B.4. You restarted Tomcat, right?
If you stopped Tomcat, you need to start it again, of course.
If you didn't stop Tomcat, you probably need to restart it.
Acknowledgements
- Drew Wills discovered this vulnerability
- James Wennmacher provided earlier drafts of documentation of it,
- Tim Levett, Tim Vertein, and especially Bas Toeter provided feedback and edits that made these instructions better.
Cover photo: Stop look and listen :