-
Notifications
You must be signed in to change notification settings - Fork 6.1k
Getting response attributes from Saml2AuthenticatedPrincipal #8667
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for such a quick response, @kostic017!
I've left some feedback inline.
...framework/security/saml2/provider/service/authentication/OpenSamlAuthenticationProvider.java
Outdated
Show resolved
Hide resolved
...framework/security/saml2/provider/service/authentication/OpenSamlAuthenticationProvider.java
Outdated
Show resolved
Hide resolved
...framework/security/saml2/provider/service/authentication/OpenSamlAuthenticationProvider.java
Outdated
Show resolved
Hide resolved
...ingframework/security/saml2/provider/service/authentication/Saml2AuthenticatedPrincipal.java
Show resolved
Hide resolved
...mework/security/saml2/provider/service/authentication/SimpleSaml2AuthenticatedPrincipal.java
Outdated
Show resolved
Hide resolved
In addition to the inline feedback, would you also please add unit tests that show the feature working? I'd recommend tests that show how attributes statements of various arrangements and data types will work. |
...framework/security/saml2/provider/service/authentication/OpenSamlAuthenticationProvider.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the edits, @kostic017! I've left a bit more feedback. Most importantly, could you add some unit tests to prove that the functionality works as intended?
...framework/security/saml2/provider/service/authentication/OpenSamlAuthenticationProvider.java
Outdated
Show resolved
Hide resolved
...k/security/saml2/provider/service/authentication/SimpleSaml2AuthenticatedPrincipalTests.java
Outdated
Show resolved
Hide resolved
...framework/security/saml2/provider/service/authentication/OpenSamlAuthenticationProvider.java
Outdated
Show resolved
Hide resolved
...framework/security/saml2/provider/service/authentication/OpenSamlAuthenticationProvider.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the updates, @kostic017! It's nice to see this taking shape.
I've left some additional feedback inline.
* @since 5.4 | ||
*/ | ||
@Nullable | ||
default <A> A getAttribute(String name) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've been putting some thought into this method, and I've got a question for you.
While the SAML spec allows multiple AttributeValue
s for a single Attribute
, it also encourages that it be one-to-one. Because of that, I imagine that most applications will want to do:
String email = principal.getAttribute("email");
instead of:
List<String> emails = principal.getAttribute("email");
String email = emails == null || emails.isEmpty() ? null : emails.get(0);
What would be your expectation?
If you'd expect to do the first option, we might want to change this method to:
List<A> values = getAttributes().get(name);
return (A) CollectionUtils.firstElement(values);
and possibly rename it to getFirstAttribute
.
If you'd expect the second option, the signature should probably change to <A> List<A> getAttribute(String)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I prefer the first option, but for one user attribute (tenant) in my app I'm expecting multiple values. Maybe we should provide both options?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I forgot about getAttributes
method. I could use it in that one case, if we only provide the first option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that to get the underlying list you can call getAttributes().get("tenant")
.
Since there is the possibility of adding both somewhere down the road, I'm leaning more heavily now towards renaming this method to getFirstAttribute
. I believe this aligns nicely with MultiValueMap
which is similar in concept and also has a method called getFirst()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, after changing getAttributes
return type, I can't do this anymore
List<String> tenants = (List<String>) principal.getAttributes().get("tenant");
since the compiler doesn't allow casting from List<Object>
to List<String>
.
And this doesn't look like a nice thing to work with:
List<Object> tenants = principal.getAttributes().get("tenant");
If I had a method like this
public <A> List<A> getAttributeValues(String name) {
return (List<A>) getAttributes().get(name);
}
I could do
List<String> tenants = principal.getAttributeValues("tenant");
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the other hand, what if those values have different types... I'm so used to working with only one value type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! A couple thoughts come to mind:
- Since this caught you and I off-guard, it would be nice if there was a test in
SimpleSaml2AuthenticatedPrincipalTests
that demonstrated the various behaviors. That way our expectations are codified in a test. - I think adding a
List
getter makes sense. An application can set the reference type toList<Object>
if their attribute contains multiple types.
Also, I'd recommend that the interface stick with getAttribute
and getFirstAttribute
. The reason for that is it aligns with similar Spring Security support for OAuth 2.0, which uses getClaim
and getAttribute
. As another example, this is the same convention followed by the Servlet spec with HttpServletRequest#getParameter
, #getAttribute
, and #getHeader
.
If you agree, then the contract would become:
Map<String, List<Object>> getAttributes();
<A> List<A> getAttribute(String name);
<A> A getFirstAttribute(String name);
...ingframework/security/saml2/provider/service/authentication/Saml2AuthenticatedPrincipal.java
Outdated
Show resolved
Hide resolved
...framework/security/saml2/provider/service/authentication/OpenSamlAuthenticationProvider.java
Outdated
Show resolved
Hide resolved
...k/security/saml2/provider/service/authentication/SimpleSaml2AuthenticatedPrincipalTests.java
Outdated
Show resolved
Hide resolved
...ringframework/security/saml2/provider/service/authentication/TestSamlResponseAttributes.java
Outdated
Show resolved
Hide resolved
@jzheaux I think you added duplicate label by mistake. |
Thanks for the additional changes, @kostic017. In preparation for merging, will you please do three more things?
|
Regarding the duplicate label, it "duplicates" the linked issue. When looking at the tickets completed in a milestone, it helps remove some noise from the report. That said, I think I should have probably waited to add it until after everything was merged, so as to create less confusion. |
NP. All done now. |
It's not possible to read attribute values from SAML response after successful login because
Saml2AuthenticatedPrincipal
doesn't havegetAttributes()
method likeOAuth2AuthenticatedPrincipal
does. I've added thegetAttributes()
method to the interface. The map is being populated inOpenSamlAuthenticationProvider
.With this patch, I won't have to parse SAML response the second time by myself if I want to read some attribute value.
fixes gh-8661