Where from does ComponentSpace Saml 2.0 take key to encrypt assertions - public-key-encryption

When I run the following code (ComponentSpace Saml 2.0 lib is used), Fiddler shows me that SAMLRequest's value is encrypted like this <input type="hidden" name="SAMLRequest" value="PHNhbWxwOkF1dGhu...."> which is pretty expected behavior. The code implements the first step of SSO SAML 2.0 POST profile. Note that no certificate key is specified in the code to do any kind of encryption, so I wonder how does ComponentSpace lib decide which one to pick up?
var authnRequest = new AuthnRequest
{
Destination = #"https://idpserver/...",
Issuer = new Issuer(#"https://sp/..."),
ForceAuthn = false,
NameIDPolicy = new NameIDPolicy(null, null, true),
ProtocolBinding = SAMLIdentifiers.BindingURIs.HTTPPost,
AssertionConsumerServiceURL = #"https://sp/..."
};
var relayState = RelayStateCache.Add(new RelayState(#"https://sp/...", null));
ServiceProvider.SendAuthnRequestByHTTPPost(
new HttpResponseWrapper(_context.Response),
#"https://idpserver/...",
authnRequest.ToXml(),
relayState);
All the Wikipedia says is "the value of the SAMLRequest parameter is the base64 encoding". No information about what the key is used to encode.

Sorry for misunderstanding your question. Your example code constructed and sent an authn request. It sounds like you're asking about SAML assertions contained in a SAML response.
The identity provider encrypts the SAML assertion using the service provider's public key. The service provider will decrypt the assertion using its private key.
If you'd like to see an example of this, please take a look at the AssertionExample project which demonstrates encrypting/decrypting SAML assertions.
Step 2 at the link you supplied describes the SP sending an AuthnRequest via HTTP/POST to the IdP. There is no XML encryption involved in sending an AuthnRequest. The XML is encoded using deflate and base-64 but no encryption. This encoding is done for you when you call ServiceProvider.SendAuthnRequestByHTTPPost.

Signing the authn request is optional.
To sign the request, before calling ServiceProvider.SendAuthnRequestByHTTPPost, you need to do something like the following:
// Serialize to XML
XmlElement authnRequestElement = authnRequest.ToXml();
// Sign the authn request
SAMLMessageSignature.Generate(authnRequestElement, x509Certificate.PrivateKey, x509Certificate);
// Send the authn request to the IdP
ServiceProvider.SendAuthnRequestByHTTPPost(..., authnRequestElement, ...);
You always sign with your private key and the recipient will verify the signature using your public key/certificate.

Related

How do I decode/decrypt Apple Server-to-Server Notifications?

My website supports Sign In with Apple.
In the configurations of this service, I have an endpoint here:
What I receive in this endpoint is a JSON like this:
"{"payload":"eyJraW...................NLnyA"}
However, I don't find absolutely anywhere how to decrypt/decode this payload...
The "Learn more" link sends me here: https://developer.apple.com/help/account/configure-app-capabilities/about-sign-in-with-apple
The page below this one is this: https://developer.apple.com/help/account/configure-app-capabilities/enabling-server-to-server-notifications
Nowhere I see how to interpret these messages...
Does anyone know what do I need to do to read these payloads?
It looks like the general procedure for Server-to-Server notifications are outlined here. This is what the docs have to say:
These notifications contain a cryptographically signed payload, in JSON Web Signature (JWS) format, signed by Apple’s private key. After your server receives a notification, examine the JWS payload and use the algorithm specified in the header’s alg parameter to validate the signature. For more information, see Fetch Apple’s public key for verifying token signature.
So, this payload is really just a JWT (verify/decode with the JWT library of your choice, there are many to choose from). Because anyone can access your endpoint, you need to verify that the token is really from Apple. Note: do not try to decode the JWT yourself. Because of security concerns, it is better to let a library do it for you.
After validating the token signature, your server performs work according to the type value in the events claim of the token. The notification payload object contains information about user-initiated account modification events.
The decoded JWT will contain something like this (example is from the docs):
{
"iss": "https://appleid.apple.com",
"aud": "com.mytest.app",
"iat": 1508184845,
"jti": "abede...67890",
"events": {
"type": "email-enabled",
"sub": "820417.faa325acbc78e1be1668ba852d492d8a.0219",
"email": "ep9ks2tnph#privaterelay.appleid.com",
"is_private_email": "true"
"event_time": 1508184845
}
}
events.type has the event that happened (full list is here), and the rest of the token contains everything else you'll need.
#Michael M.'s answer helped me understanding that this payload is basically a JWT.
This is what we need to do (minimal example):
use Firebase\JWT\JWK;
use Firebase\JWT\JWT;
$json = json_decode(file_get_contents('php://input'));
$publicKeys = json_decode(file_get_contents('https://appleid.apple.com/auth/keys'), true);
$decodedPayload = JWT::decode($json->payload, JWK::parseKeySet($publicKeys));
var_dump($decodedPayload);

How to proof that a JWT is truly valid?

This is my Service for generating JWTs in my Project. This, works, a user can login, retrieve a JWT and do operations with this token until its expires.
#Singleton
public class JwtService {
public String generateUserJwt() {
return generateJsonWebToken(Set.of(Role.USER));
}
public String generateAdminJwt() {
return generateJsonWebToken(Set.of(Role.ADMIN));
}
public String generateSuperAdminJwt() {
return generateJsonWebToken(Set.of(Role.USER, Role.ADMIN));
}
private String generateJsonWebToken(Set<Role> roles) {
Set<String> groups = Set.of(roles.stream().map(Role::getValue).toArray(String[]::new));
return Jwt.issuer("https://example.com")
.subject("myproject-2022-jwt")
.upn("myproject-2022-jwt")
.claim(Claims.birthdate.name(), "1985-10-25")
.groups(groups)
.expiresAt(System.currentTimeMillis() + 3600)
.sign();
}
}
Problem
Let say a User login, 10 seconds later I ban/delete his account. His JWT is still valid and he can do requests with postman using last JWT.
How I can handle this?
You can't.
The entire purpose of a JWT is to be self sustained and independent. This is why its never recommended to expose JWTs to external clients. Even though people do this all the time.
The rfc for JWTs states the following:
JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between two parties. [...] enabling the claims to be digitally signed or integrity protected with a Message Authentication Code (MAC) and/or encrypted.
In this context, "claim" can be something like a 'command', a one-time authorization, or basically any other scenario that you can word as:
Hello Server B, Server A told me that I could , and here's the (cryptographic) proof.
This is why you need to have short lived JWT that are only valid for minutes. Because if one gets compromised you can't block/logout that user.
OWASP mentions this in their cheat sheet series, and their solution for mitigation is to implement a block list, but remember that once you do that, the entire solution is not stateless anymore, and you need to share this block list over multiple servers.
Which basically means you can use cookie sessions, as they have more protection and fulfills the same purpose.
Using JWTs as session bearers has always been a bad idea and has been mentioned over and over:
Even back in 2016 it was not advised:
Stop using JWT for sessions part 1
Stop using JWT for sessions part 2
Redis blog:
JSON Web Tokens (JWT) are Dangerous for User Sessions
Okta blog:
Why JWTs suck as user sessions

How to add #RequestBody to variables?

#PostMapping("/api/v1.0/{username}/forgot")
public void forgotPassword(#PathVariable String username,#RequestBody String enteredPassword,#RequestBody String reenterPassword) {
userServiceImpl.forgotPassword(username, enteredPassword, reenterPassword);
}
Here if the user wants to perform forgot password action he need to enter the password so how can i request user values from postman
Resolved [org.springframework.web.bind.MissingPathVariableException: Required URI template variable 'email' for method parameter type String is not present]
I am getting this error
RequestBody Annotation is generally used when you are not sure of the size of the data you will be sending to backend, for example : large JSON objects.
In your case I see you want to pass the username and password so will recommend you to go with Request Headers (preferably with some authentication methods to encrypt and decrypt the password, just to avoid plaintext password getting passed) instead of Request Body. There is a tab in postman from where you can pass the headers in key and value pairs. I would recommend you to check this link illustrating the use of Request headers.

Slack - How to verify interactivity requests

Setting up my first Slack slash command. I built it out originally using the deprecated verification token but, for posterity, have decided to use signed secrets authentication.
Reading through the signed secrets documentation, I've had no issue validating requests that come in from the initial slash command. However, interaction requests have a completely different body structure and the method for calculating a secret hash do not produce a valid result (because the request body is different).
Here is a snippet from the docs on validating signed secrets.
slack_signing_secret = 'MY_SLACK_SIGNING_SECRET' // Set this as an environment variable
>>> 8f742231b10e8888abcd99yyyzzz85a5
request_body = request.body()
>>> token=xyzz0WbapA4vBCDEFasx0q6G&team_id=T1DC2JH3J&team_domain=testteamnow&channel_id=G8PSS9T3V&channel_name=foobar&user_id=U2CERLKJA&user_name=roadrunner&command=%2Fwebhook-collect&text=&response_url=https%3A%2F%2Fhooks.slack.com%2Fcommands%2FT1DC2JH3J%2F397700885554%2F96rGlfmibIGlgcZRskXaIFfN&trigger_id=398738663015.47445629121.803a0bc887a14d10d2c447fce8b6703c
On invocation of the slash command this works as intended - the request body matches the structure in the example above. When the user interacts with the message, the response body uses the blocks api - which is completely different
If I'm not supposed to use the verification token and the request body from the interactive blocks api does not allow me to compute a valid hash, how am I supposed to validate interaction requests? I must be missing something while combing through the docs.

How to find out which public key to use to verify a JWT signature

I am trying to implement Sign In with Apple. I have an id_token which is a jwt token having kid value in the header. When I fetch the auth keys from Apple I see that it returns more than 1 auth key. What is the efficient way of finding out which among these keys can be used validate the signature in the id_token as I do not want to loop through each public key. Looping through will result in unnecessary signature validation failures.
String[] parts = idToken.split("\\.");
String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]));
System.out.println(headerJson);
This will give the header and we can compare and then validate the signature.
Backend – Token verification
get kid from identityToken.
[[NSString alloc] initWithData:credential.identityToken
encoding:NSUTF8StringEncoding]
then match kid given by apple server

Resources