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

Handle incoming AuthnRequests #52018

Merged
merged 12 commits into from
Feb 26, 2020

Conversation

jkakavas
Copy link
Member

@jkakavas jkakavas commented Feb 6, 2020

  • Expose an API that consumes (possibly signed) AuthnRequests as
    defined by the HTTP-Redirect binding.
  • Process AuthnRequests, validate and parse them into a minimum
    set of information to be used for subsequent API calls to get a
    SAML Response

- Expose an API that consumes (possibly signed) AuthnRequests as
defined by the HTTP-Redirect binding.
- Process AuthnRequests, validate and parse them into a minimum
set of information to be used for subsequent API calls to get a
SAML Response
@jkakavas jkakavas added the :Security/Security Security issues without another label label Feb 6, 2020
@jkakavas jkakavas requested a review from tvernum February 6, 2020 21:53
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-security (:Security/Security)

Copy link
Contributor

@tvernum tvernum left a comment

Choose a reason for hiding this comment

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

I didn't finish the review, but I think there's enough to go on for now.

@jkakavas
Copy link
Member Author

address feedbacl and add Transport action tests

Mixed up commit messages thinking about #51830. I didn't add Transport action tests here as all it does in doExecute is to call processQueryString

@tvernum
Copy link
Contributor

tvernum commented Feb 17, 2020

I'm going to hold off re-reviewing this until the other handler PR is merged. I think we're good, but the merge is going to be a bit messy.

@jkakavas
Copy link
Member Author

I'm going to hold off re-reviewing this until the other handler PR is merged. I think we're good, but the merge is going to be a bit messy.

This is ready @tvernum

this.clock = clock;
this.idp = idp;
this.builderFactory = XMLObjectProviderRegistrySupport.getBuilderFactory();
Copy link
Contributor

Choose a reason for hiding this comment

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

What's the reason for dropping the SamlFactory ?

Copy link
Member Author

Choose a reason for hiding this comment

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

I thought that SamlUtils covers the functionality and purpose so there was no reason to have both and I moved relevant parts from SamlFactory to SamlUtils ( this is more or less what we do in the saml realm implementation ).

If you feel that we should split somehow ( Instance with initialization for loggers in Factory and all static methods in Utils for instance ) I'm happy to discuss or just do it. I have no strong preference

Copy link
Contributor

Choose a reason for hiding this comment

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

I found SamlUtils in security to have been a bit overloaded, and was hoping to avoid replicating it here. I'm not stuck on it, I just have an aversion to catch-all utility classes.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thinking this through again and seeing that I've made all methods in SamlUtils static already, I'm not sure what distinction would make sense. As in what should be in Utils and what should be in the Factory class. At 300 loc, SamlUtils doesn't seem too bloated atm.

I'm open to suggestions on what should be split away and back to a Factory class, or we could merge as is and spit these somehow once/if SamlUtils gets too bloated/overloaded

Copy link
Contributor

Choose a reason for hiding this comment

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

This is definitely a personal preference thing, so I'm OK with merging as-is (though, in terms of preferences, I preferred the existing code).

Issues with Utility classes:

  1. They become a catch-all dumping ground that becomes a cheap answer when something is needed, and avoids doing the harder design thinking. A good chunk of Utility class methods are working around broken class design that ideally would be fixed up front (but sometimes you have to because the broken class is in the JDK).
  2. Related to the above, they often end up with a weird mix of responsibilities/behaviours. Because they're just chunks of code that "do something, that someone thought was useful", they typically don't go through the process of Is this the right behaviour for this method?.
  3. Related to that, they can be hard to test well, unless they've got a clear interface & a single purpose (those are the best kind of utility method).
  4. More importantly, it becomes hard to test code the uses utility methods. They can't be mocked (because they're static), and it's often hard to trigger some of the behaviours that you need. As an example, while writing tests for SSL error messages, it was almost impossible to force PemUtils to throw certain exceptions so that I could verify they were handled neatly.
  5. It can be hard to find the right method, because of the dumping ground problem. Ever tried to find the right helper method in amongst XContentUtils, XContentParserUtils, XContentHelper, XContentTestUtils ?

Now, you're probably thinking Wait, SamlUtils and SamlFactory makes problem 5 worse. And that's true, but SamlInit and SamlFactory were clear. It's when we decide to take the easy option and just have a Utils class that we lose clarity about what we each class is supposed to do.

However, as I said, personal preference. This definitely isn't a hill I'd die on. But those are the sorts of reasons why I tried to start with SamlInit and SamlFactory for this project.

Copy link
Member Author

Choose a reason for hiding this comment

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

No need for anyone to die on this hill :) Given we've put in the time to climb it already though, I'll try and come up with something that you feel better with. I'll put the initialization logic in SamlInit to we can call initialize() on it and then move things back to a SamlFactory class which we can instantiate and call methods on.

@tvernum
Copy link
Contributor

tvernum commented Feb 24, 2020

@elasticmachine update branch

@elasticmachine
Copy link
Collaborator

merge conflict between base and head

public <T extends XMLObject> T object(Class<T> type, QName elementName) {
final XMLObject obj = builderFactory.getBuilder(elementName).buildObject(elementName);
return cast(type, elementName, obj);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Putting aside the SamlUtils vs SamlFactory question, why move these methods here?
Surely we'll need them again when handling logout requests/response & authn failures.

} catch (URISyntaxException e) {
throw new IllegalArgumentException("Invalid URI for Assertion Consumer Service", e);
}
this.assertionConsumerService = assertionConsumerService;
Copy link
Contributor

Choose a reason for hiding this comment

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

I still feel like this should be a URI. It is a URI and I think we should consistently treat it like one.

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't necessarily agree that this is important.

I reverted the change as you requested. There is value in validating that it is a URL (it's a URI but we should not be validating for a URI, as it can't be a URN ) and we will be doing this in the Registration API , no harm in doing it here too. Again, I think that for all intents and purposes when it comes to SAML, handling this as a URL in code - after validation - is unnecessary and it can potentially introduce subtle bugs.
For instance we need to take care so that when comparing ACS values , we are comparing string representations of the URLs and i.e. not URL.equals which does something different.

I didn't change the IDP configuration settings to be Setting<URL> too because of the arguments here, the fact that we already validate them and finally that we have no good existing way to parse and handle Setting<URL> with optional values in a way that makes sense to me ( I can further elaborate if needed )

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm moving these to Setting in the IDP metadata PR

@@ -38,7 +48,12 @@ public String getEntityId() {
}

@Override
public URI getAssertionConsumerService() {
public String getNameIDPolicyFormat() {
return nameIdPolicyFormat;
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we make this a Set since we've done that with the index?

@jkakavas jkakavas merged commit eaa2e4f into elastic:feature-internal-idp Feb 26, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
:Security/Security Security issues without another label
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants