Skip to content
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

SAML 2.0 Single Logout Support #9483

Merged
merged 5 commits into from
Sep 13, 2021
Merged

Conversation

jzheaux
Copy link
Contributor

@jzheaux jzheaux commented Mar 2, 2021

No description provided.

@jzheaux jzheaux self-assigned this Mar 2, 2021
@jzheaux jzheaux added in: saml2 An issue in SAML2 modules type: enhancement A general enhancement labels Mar 2, 2021
@jzheaux jzheaux added this to the 5.5.0-M3 milestone Mar 2, 2021
@jzheaux jzheaux force-pushed the saml2-logout branch 6 times, most recently from a88c1b1 to ddf8e7a Compare March 5, 2021 23:08
@jzheaux jzheaux marked this pull request as ready for review March 5, 2021 23:08
Copy link
Contributor

@fhanik fhanik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Josh, I decided to pause the review,, to grasp more around the configuration choice.

Copy link
Contributor

@fhanik fhanik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Josh, I've given you some to work with.

The number 1 take away I have is that Spring Security shouldn't release 2nd class citizen implementations. That being, I have to jump through hoops like configuring logout handlers, filters, etc to just get something as basic as logout to work. This seems to contradict the reason why we have Spring Security, like logout() in the DSL

I am happy to review the next, I need to get my environment setup for that

@jzheaux jzheaux force-pushed the saml2-logout branch 2 times, most recently from 2ee9b25 to f16548f Compare March 30, 2021 23:42
Copy link
Contributor

@fhanik fhanik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Big ticket items

  1. Metadata shows Single Logout Services even when single logout isn't enabled
  2. is there one /logout that is handles logout for any type of authentication or is there /<auth-type>/logout and thus, if you support oidc,saml,oauth2,internal you have four different logout endpoints

Overall, this looks very promising and I think the above comments can be saved for future iterations as the community gets a chance to test drive it.

Copy link
Member

@rwinch rwinch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've provided some feedback inline

@jzheaux
Copy link
Contributor Author

jzheaux commented Apr 12, 2021

This was merged in commits efe42b9, 2f734a0, e807fae, and 6f52bab, closing the corresponding issue for each one.

Copy link
Contributor

@fhanik fhanik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the hard work on this.

@jzheaux
Copy link
Contributor Author

jzheaux commented Apr 16, 2021

I've reopened the PR to take a closer look at this comment.

@jzheaux jzheaux force-pushed the saml2-logout branch 2 times, most recently from ebf88c5 to 2c6c988 Compare May 11, 2021 23:30
@jzheaux jzheaux force-pushed the saml2-logout branch 8 times, most recently from 4d82f8c to 6038bdb Compare July 16, 2021 06:45
Copy link
Member

@rwinch rwinch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've provided feedback inline.

public interface RelyingPartyRegistrationResolver extends Converter<HttpServletRequest, RelyingPartyRegistration> {

@Override
default RelyingPartyRegistration convert(HttpServletRequest request) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer to leave this method off of the new interface. Instead, I think it would be worth seeing if the following arrangement would work:

  • RelyingPartyRegistrationResolver does not extend Converter
  • DefaultRelyingPartyRegistrationResolver can implement both Converer and RelyingPartyRegistrationResolver
  • Classes that use to use Converter<HttpServletRequest, RelyingPartyRegistration> can now also allow RelyingPartyRegistrationResolver to be injected

In my mind this has the following advantages:

  • RelyingPartyRegistrationResolver is kept cleaner because it does not need the convert method
  • Classes that use to use Converter no longer need use instanceof checks (i.e. SamlMetadataFilter) because there can be distinct constructors/methods for the types.
  • We can properly deprecate the old Converter methods/constructors
  • We can properly deprecate the old DefaultRelyingPartyRegistrationResolver.convert method which eventually allows us to remove it's RequestMatcher that may be out of sync with the way the Filter is resolving the registrationId.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this raises a passivity concern. For example, a current construction of Saml2MetadataFilter could look like:

new Saml2MetadataFilter(
    new DefaultRelyingPartyRegistrationResolver(repository), new OpenSamlMetadataResolver())

If RelyingPartyRegistrationResolver does not extend Converter, then Saml2MetadataFilter will need another constructor, one that takes RelyingPartyRegistrationResolver. Since DefaultRelyingPartyRegistrationResolver extends both, the constructor call is ambiguous, causing a compilation error.

One way to address this would be to add a static factory method Saml2MetadataFilter#construct(RelyingPartyRegistrationResolver, Saml2MetadataResolver). This method would be necessary in other classes like Saml2AuthenticationTokenConverter.

Or, if we add the new constructors and deprecate the old ones, those who upgrade can change to the other constructor by adding a cast like so:

new Saml2MetadataFilter((RelyingPartyRegistrationResolver) 
    new DefaultRelyingPartyRegistrationResolver(repository), new OpenSamlMetadataResolver())

or by splitting up the line (more readable anyway):

RelyingPartyRegistrationResolver relyingPartyRegistrationResolver = 
    new DefaultRelyingPartyRegistrationResolver(repository);
new Saml2MetadataFilter(relyingPartyRegistrationResolver, new OpenSamlMetadataResolver())

The initial construction I listed may be uncommon and is certainly less readable -- what are your thoughts?

}
this.logoutHandler.logout(request, response, authentication);
Saml2LogoutResponse logoutResponse = this.logoutResponseResolver.resolveLogoutResponse(request, authentication)
.logoutResponse();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is worth separating the controller and the view so users can customize the UI without needing to do the more complex controller logic. We can allow this Filter to optionally forward to a URL that obtains the Saml2LogoutResponse from a HttpServletRequest attribute so it can render it's own UI. This could be logged as a separate ticket. The code below would become a default ui if no forward URL was provided.

@jzheaux jzheaux merged commit 4f06fc6 into spring-projects:main Sep 13, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: saml2 An issue in SAML2 modules type: enhancement A general enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants