Getting access token with client credentials and X509 certificate (Identity Server 4) - identityserver4

i'm looking for a solution for 4 days but i have found nothing.
What i want is to get an access token from my Identity Server with a client_credentials grant_type. I found that you can do this but nowhere is explained how to make the certificates, how the request is made etc.
I tried a lot of ways but with no success.
From the documentation:Our default private key JWT secret validator expects the full (leaf) certificate as base64 on the secret definition. This certificate will then be used to validate the signature on the self-signed JWT . That base64 is the content of the .cert file i believe. On the request should i put the .pfx file in base64 too?
Are there any changes that i need to make on the program.cs file for the Kestrel? I found this too, but all are outdated and doesn't work.
Now i'm trying with postman, after this everything should be called from an Azure Logic App.
I followed this example : but doesn't work.
The error:
Postman:
Program.cs
And the Config.cs from Identity
I will be very glad if you can help. Thanks in advance

As said you can use a client secret instead of a client certificate which is more common/easier. If you really need certificate authentication: I found more information on http://docs.identityserver.io/en/latest/topics/mtls.html

Related

How can I convert my pfx-file to a byte[] for use in API-Management?

Problem:
Sending a request from Azure-API-Management to a SOAP-webservice using client certificate authentication, results in a 401-response, whereas I would like to get a 200-response.
Cause: When I use the same keystore (pfx) in SoapUI all goes well and I do receive the 200-response. So the certificates and key in the pfx are valid. Because Basic Authentication in APIM does allow me to connect to the webservice, the cause must be that something goes wrong with sending the client-certificate from API-Management to the webservice.
Attempt to solve: I would like to try sending the certificate to the backend using this policy so I can hopefully pass the authentication:
<authentication-certificate body="#(context.Variables.GetValueOrDefault<byte[]>("byteCertificate"))" password="optional-certificate-password" />
Where I am currently stuck:
How can I convert my PFX file (containing 4 certificates and a key) to a byte array so that I can use it in API-Management?

Sending pfx certificate in angular $http call

I have an external API that I'm using: https://example.com/. When browsing to this, I get a popup that asks for a certificate, which I have as a .pfx file (or in my keychain as a .cer). I accept that they access the certificate and sign it with my private key and voilà - I can access the page.
Now what I want to be able to do is do this in AngularJS. What I have tried so far is:
$http.get("https://example.com/");
Response:
Failed to load resource: The server ”...” did not accept the certificate. - I translated this from another language, just so you know.
What I want to do is to somehow send the .pfx file in the $http request. How do I do this?
I solved this by doing it in node.js instead, where there are options for certificates. I used pfx and passphrase and that was it. I however don't know if this is possible to do in AngularJS.

What happens during a AcquireTokenAsync call using the client certificate?

In Azure AD, when we make a call such as AuthenticationContext.AcquireTokenAsync(resource, new ClientAssertionCertificate(_clientId, _cert)) it is not clear what exactly happens.
What part of the certificate gets exchanged if any?
Is there a challenge/response taking place?
Is the private key needed on the client as a part of this?
There are two ways you could go about finding the answer to you questions. One would be to look at the Microsoft Active Directory Authentication Library (ADAL) for .NET source code on GitHub, since this is open-source. The other (which we'll do here) is to looking at the network request that AcquireTokenAsync(String, ClientAssertion) generates, and work backwards from there.
Using Fiddler (or any other traffic analyzer), we can see something like the following (formatted for readability):
POST https://login.microsoftonline.com/{tenant-id}/oauth2/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&resource=https%3A%2F%2Fgraph.windows.net
&client_id={app-id}
&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer
&client_assertion=eyJhbGciOiJSUzI1N...VE8wHSf-HZvGQ
Breaking it down:
grant_type=client_credentials tells us this is a token request using the OAuth 2.0 Client Credentials Grant flow.
resource=https%3A%2F%2Fgraph.windows.net gives the URI of the resource the client is requesting an access token for. In this case, it's for the Azure AD Graph API.
client_id={app-id} is the client identifier. In Azure AD, this is the app ID of the application that was registered.
The presence of client_assertion_type and client_assertion are indicative that the client is using an assertion to authenticate:
client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer says that client assertion being used is a signed JSON Web Token (JWT).
client_assertion=eyJhbGciOiJSUzI1N...VE8wHSf-HZvGQ is the aforementioned signed JWT token. The authorization server (e.g. Azure AD) will validate the contents, and check that the token was indeed signed by the certificate authorized for the client in question.
So, what ADAL does is:
Construct a token with a set of claims about the client (your app)
Use your certificate's private key to generate a cryptographic signature of those claims
Bundle that up into a signed JWT
Make an appropriately formed token request to the authority
During AcquireTokenAsync, only the certificate's thumbprint is provided (it's included in the JWT header to help the authorization server look up the corresponding public key). The JWT's signature is what proves that the client is in possession of the private key. However, before AcquireTokenAsync(String, ClientAssertion) can be used successfully, the client owner (i.e. you) needs to have provided Azure AD with the certificate's public key.
There is no challenge/response taking place here. The token is obtained in a single request, initiated by the client.
For a lot more detail, you can review the standards that this all implements:
RFC 6749: The OAuth 2.0 Authorization Framework
RFC 7521: Assertion Framework for OAuth 2.0 Client Authentication and Authorization Grants
RFC 7523: JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants
RFC 7519: JSON Web Token (JWT)
(Note that ADAL has a cache. Everything I described above will take place only if ADAL does not find a valid access token in the token cache. You can use AuthenticationContext.TokenCache.Clear() to clear the cache for experimentation.)

How to test client certificate

I'm building a web service to allow salesforce to call to it, the two way SSL is used for security, and salesforce has provided its client certificate: sfdc-client.cert.
In order to test whether salesforce client certificate work or not, I have setup a very simple web on MAC apache and enable SSL and client authentication on ssl config file /etc/apache2/extra/httpd-ssl.conf as below (use self-signed):
SSLCertificateFile "/private/etc/apache2/ssl/server.crt"
SSLCertificateKeyFile "/private/etc/apache2/ssl/server.key"
SSLCACertificateFile "/private/etc/apache2/ssl/sfdc-client.cert"
SSLVerifyClient require
SSLVerifyDepth 10
The first browsing by Chrome, I got "SSL Connection Error", I supposed it's correct in this case.
Then, I have tried to import sfdc-client.cert to key chain access, but it does not work at all because it just supports p12/pfx format.
I also tried to use CURL:
curl https://test.com --cert-type der --cert sfdc-client.cert
but got the error:
curl: (58) unable to use client certificate (no key found or wrong pass phrase?)
I'm totally newbie on this stuff, does anyone know how to test client certificate to make sure it works as above?
First you need to have both the client's certificate and certificate private key to be able to test 2-way SSL authentication.
To test with web browser, follow instructions here: Is there a way to test 2 way ssl through browser?

Why do I need to share the certificate with an SP for SSO when the certificate is included in the signed SAML response?

I am just wondering while implementing SAML SSO with Salesforce I realize that I uploaded the certificate to the SP side (i.e. Salesforce), however I can see when we send a signed SAML response it already includes the certificate.
Why is the certificate shared ahead of time with the SP?
It's all about establishing trust between systems. If you don't give SFDC your cert ahead of time, how can they trust the message you are sending is actually from your IDP? Without your cert ahead of time, they can validate that the message is intact but not who actually generated it. When you include your public key in the SAML Response, they can check that it's the same one you shared with them and it's the same one you used to generate the signature.

Resources