Saml2-bearer (authorization grant)
onelogin/php-saml is a required (suggested) dependency for this to work because its used to do all the hard work to validate the token.
All the configuration is passed through the $settings param in the constructor. That includes the 'audience' ( in saml2 it's 'sp'->'entityID'), the 'issuer' ('idp'->'entityID'), certificates, and other configuration that must be consistent with the IDP configuration like NameIDFormat, which attributes are encrypted/signed, etc.
An out of scope, but important problem is how to generate a valid Saml2 assertion to be used here. I opened an issue on simplesaml (which imiplements an IDP) simplesamlphp/simplesamlphp#172. Let's see how it goes.
The main problem is that the one who asks for the saml2 token (that's a trusted party which wants to get an access_token to access the user's data), has to generate/get a token crafted specially for Oauth2 Server. So it either behaves as an idp, or asks the idp for those.
For now, OneLogin has a 'strict' param which disables most of the validations and makes everything work; e.g. grants an access_token.
PS: It's not necessary to merge the PR, it has no BC but we may need to solve the aforementioned problem and do further testing. I just wanted to share the code.
Update: Saml2 (Authorization Grants) grant type is not a ClientAssertionType. In fact, the draft states that client authentication is optional. Though it has another use for Client Authentication which obviously is a ClientAssertionType. But we may need to handle both separately.
I'm a little confused about how this should really be used in production. Here I link some real implementations, which have some differences and dont' give away all details: case 1) Pint Identity case 2) wso2
case 3) salesforce
This looks great! I would appreciate a rebase of all of these commits into a single commit using git rebase -i HEAD~9
As far as how this is used... I honestly don't really know... but before merging I will definitely try to put this together. We will want documentation on this as well.
I agree with all recommendations. I'll make them asap.
Regarding usage, I think that the server itself is compliant with the saml2-draft. What is missing is a way to generate valid assertions (in PHP at least), but it's kind of out of scope here.**
I'll drop some docs at the sample project (https://github.com/aacotroneo/saml2-bearer-server) we can put that elsewhere later.
** I'm using this grant right now. Due to this limitation, I had to drop some validations (one-login's 'strict=false' setting), but are instead made by the oauth clients (existing service providers). In this limited case, all parties need to be 100% trusted, but I can reuse the existing saml2 assertion as an implicit user authorization. Basically, each service provider 'transforms' its saml2 assertion into a oauth token to use some rest apis.
Thank you for making those changes
I was able to get your slim project up and running! Nice work. However, I do not see an easy way to create the SAML assertion. Can you provide some sample code on how to do this?
Right now I have a simplesamlphp server installed (with corresponding idp's) and use that (with aforementioned limitations). That's pretty heavy to make a simple integration test.
I know that's no good. I can design some tests. I'm thinking about reusing some of the test assertions that onelogin uses in their tests. That will at least be enough to tests basic stuff.
@aacotroneo Okay, I spent a little bit revisiting this, and I have a few thoughts/suggestions.
- Is the reason we have to turn "strict" to "false" because we are required to have an SSL Certificate signed by a root authority?
- I think we should just pass the
OneLogin_Saml2_Responseobject into the constructor of theSaml2Bearergrant type Saml2Bearershould implementClientAssertionTypeinterface, and should definitely return aclient_idvia the functiongetClientId, otherwise how do we know which client issued the token?
What are your thoughts?
1 - This is what onelogin's says about it:
If 'strict' is True, then the PHP Toolkit will reject unsigned or unencrypted messages if it expects them to be signed or encrypted. Also it will reject the messages if the SAML standard is not strictly followed: Destination, NameId, Conditions ... are validated too.
Note that this will be a user's configuration, based on their infrastructure. It's not quite our problem right now (though it would be nice to have a nice working case).
I couldn't create a strictly valid token to use in my infrastructure (with existing tools), so I use strict = false.
2 - I just decoupled implementation onto the other objects in case we find another impl and to ease unit testing (I tried to avoid using real assertions in tests). Anyway it's just a code style, if you think that way is more consistent to the rest of the code, It's ok for me.
3 - Note that this PR covered the authorization grant flow only. If I'm understanding correctly from the draft, it's not the client who issues the token. The client does not even appear on the assertion (it does for the client-auth flow but as the 'subject', not the issuer). The draft states that you may however use this flow with client credentials (client_id, client_secret), and they are correctly handled by the tokenController.
@aacotroneo @bshaffer I raise the subject ! Can I use this to implement SAML2 into my oauth2 server ? Is it stable ? Can you merge this PR ? Thank you for your comeback !!
Im not working with it anymore. But it's not a saml server. You basically pass a saml token (proof that you are auth'ed) and you get a oauth token.
Any update on this?