indigo-iam/iam

oidc auth failed to handle special characters

Opened this issue · 6 comments

Hi,

When client_id or client_secret include special characters like "+", the IAM will not be able to be authorized correctly.
Here is the problem part.

String auth = clientConfig.getClientId() + ":" + clientConfig.getClientSecret();

Below is the corresponding python codes. It works ok to be authorized which IAM cannot.
`
credentials = "{}:{}".format(quote_plus(client_id), quote_plus(client_secret))

authz = base64.b64encode(credentials.encode("utf-8")).decode("utf-8")
`

Hi, not sure if we got your point: you have registered a client where the client_id or secret has spaces for instance?

If yes, you don't have to URI-encode them before to build the base64 encoded authorization header.

For instance, if my client_id is client id (with client-credentials grant), the curl command to request a token would be something like

curl -u "client id":secret https://iam.test.example/token -d grant_type=client_credential

The client_id is ok. The case is that the client_secret has a '+'.
We have tested different cases. It's ok if the client_secret includes '/'. However, it will not work if the client_secret includes '+' (Using python script with 'quote_plus' to convert the '+' character, it works ok).

Hi,

I tried with a client having sec+ret as client_secret and it works!

This is the request to the token endpoint:

curl -H 'Authorization: Basic <authz>' -d grant_type=client_credentials http://localhost:8080/token

I used your python code, but without quote_plus.

We tried it against dexidp. With "+", Indigo IAM will fail in authentication while the python script works. Without "+", Indigo IAM works ok.

Sorry, it's not clear to us why you're using that quote_plus method (or any other quote method). These methods escape special characters so the client_id|secret totally changes its value before base64 encoding. Then IAM decodes a completely different credential from what it has been saved on its database. It does only a base64 decode. That's probably the reason of your error.

For example, if we have:

client_id = "client id with+"
client_secret = "client secret with+"

the base64 encoding of {client_id}:{client_secret} is:

Y2xpZW50IGlkIHdpdGgrOmNsaWVudCBzZWNyZXQgd2l0aCs=

If we apply quote_plus to client_id and client_secret we obtain new credentials:

client_id = quote_plus("client id with+") // it's "client+id+with%2B"
client_secret = quote_plus("client secret with+") 

Then, the base64 encoding of {client_id}:{client_secret} is different:

Y2xpZW50K2lkK3dpdGglMkI6Y2xpZW50K3NlY3JldCt3aXRoJTJC

Sample test here https://workat.tech/codes/e3lkttxn.

Moreover, the Basic Authn specification simply says that:

To receive authorization, the client
   1.  obtains the user-id and password from the user,
   2.  constructs the user-pass by concatenating the user-id, a single colon (":") character, and the password,
   3.  encodes the user-pass into an octet sequence (see below for a discussion of character encoding schemes),
   4.  and obtains the basic-credentials by encoding this octet sequence using Base64 into a sequence of US-ASCII characters.

I knew the encoded result from IAM log is different from the python method. Without the '+', both of them work.
With '+', the IAM way doesn't work.
By the way, in the log, header has a content-type: "application/x-www-form-urlencoded;charset=UTF-8".

2023-06-05 08:31:16.255 DEBUG 7 --- [nio-8443-exec-3] org.apache.http.headers : http-outgoing-1 >> Content-Type: application/x-www-form-urlencoded;charset=UTF-8

https://github.com/CZ-NIC/pyoidc/blob/5245dca7e462aae88902f9763d31a7cceb25ff44/src/oic/utils/authn/client.py#L124C1-L126