mirror of
https://github.com/minio/minio.git
synced 2025-04-10 06:30:07 -04:00
fix: allow audience claim to be an array (#12810)
Some incorrect setups might have multiple audiences where they are trying to use a single authentication endpoint for multiple services. Nevertheless OpenID spec allows it to make it even more confusin for no good reason. > It MUST contain the OAuth 2.0 client_id of the > Relying Party as an audience value. It MAY also > contain identifiers for other audiences. In the > general case, the aud value is an array of case > sensitive strings. In the common special case > when there is one audience, the aud value MAY > be a single case sensitive string. fixes #12809
This commit is contained in:
parent
aa0c28809b
commit
3735450e7e
@ -59,6 +59,7 @@ const (
|
|||||||
expClaim = "exp"
|
expClaim = "exp"
|
||||||
subClaim = "sub"
|
subClaim = "sub"
|
||||||
audClaim = "aud"
|
audClaim = "aud"
|
||||||
|
azpClaim = "azp"
|
||||||
issClaim = "iss"
|
issClaim = "iss"
|
||||||
|
|
||||||
// JWT claim to check the parent user
|
// JWT claim to check the parent user
|
||||||
@ -333,9 +334,40 @@ func (sts *stsAPIHandlers) AssumeRoleWithSSO(w http.ResponseWriter, r *http.Requ
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var audFromToken string
|
// REQUIRED. Audience(s) that this ID Token is intended for.
|
||||||
if v, ok := m[audClaim]; ok {
|
// It MUST contain the OAuth 2.0 client_id of the Relying Party
|
||||||
audFromToken, _ = v.(string)
|
// as an audience value. It MAY also contain identifiers for
|
||||||
|
// other audiences. In the general case, the aud value is an
|
||||||
|
// array of case sensitive strings. In the common special case
|
||||||
|
// when there is one audience, the aud value MAY be a single
|
||||||
|
// case sensitive
|
||||||
|
audValues, ok := iampolicy.GetValuesFromClaims(m, audClaim)
|
||||||
|
if !ok {
|
||||||
|
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue,
|
||||||
|
errors.New("STS JWT Token has `aud` claim invalid, `aud` must match configured OpenID Client ID"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !audValues.Contains(globalOpenIDConfig.ClientID) {
|
||||||
|
// if audience claims is missing, look for "azp" claims.
|
||||||
|
// OPTIONAL. Authorized party - the party to which the ID
|
||||||
|
// Token was issued. If present, it MUST contain the OAuth
|
||||||
|
// 2.0 Client ID of this party. This Claim is only needed
|
||||||
|
// when the ID Token has a single audience value and that
|
||||||
|
// audience is different than the authorized party. It MAY
|
||||||
|
// be included even when the authorized party is the same
|
||||||
|
// as the sole audience. The azp value is a case sensitive
|
||||||
|
// string containing a StringOrURI value
|
||||||
|
azpValues, ok := iampolicy.GetValuesFromClaims(m, azpClaim)
|
||||||
|
if !ok {
|
||||||
|
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue,
|
||||||
|
errors.New("STS JWT Token has `aud` claim invalid, `aud` must match configured OpenID Client ID"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !azpValues.Contains(globalOpenIDConfig.ClientID) {
|
||||||
|
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue,
|
||||||
|
errors.New("STS JWT Token has `azp` claim invalid, `azp` must match configured OpenID Client ID"))
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var subFromToken string
|
var subFromToken string
|
||||||
@ -349,12 +381,6 @@ func (sts *stsAPIHandlers) AssumeRoleWithSSO(w http.ResponseWriter, r *http.Requ
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if audFromToken != globalOpenIDConfig.ClientID {
|
|
||||||
writeSTSErrorResponse(ctx, w, true, ErrSTSInvalidParameterValue,
|
|
||||||
errors.New("STS JWT Token has `aud` claim invalid, `aud` must match configured OpenID Client ID"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var issFromToken string
|
var issFromToken string
|
||||||
if v, ok := m[issClaim]; ok {
|
if v, ok := m[issClaim]; ok {
|
||||||
issFromToken, _ = v.(string)
|
issFromToken, _ = v.(string)
|
||||||
|
@ -121,7 +121,7 @@ $ go run web-identity.go -cid 204367807228-ok7601k6gj1pgge7m09h7d79co8p35xx.apps
|
|||||||
- Visit http://localhost:8080, login will direct the user to the Google OAuth2 Auth URL to obtain a permission grant.
|
- Visit http://localhost:8080, login will direct the user to the Google OAuth2 Auth URL to obtain a permission grant.
|
||||||
- The redirection URI (callback handler) receives the OAuth2 callback, verifies the state parameter, and obtains a Token.
|
- The redirection URI (callback handler) receives the OAuth2 callback, verifies the state parameter, and obtains a Token.
|
||||||
- Using the access token the callback handler further talks to Google OAuth2 Token URL to obtain an JWT id_token.
|
- Using the access token the callback handler further talks to Google OAuth2 Token URL to obtain an JWT id_token.
|
||||||
- Once obtained the JWT id_token is further sent to STS endpoint i.e MinIO to retrive temporary credentials.
|
- Once obtained the JWT id_token is further sent to STS endpoint i.e MinIO to retrieve temporary credentials.
|
||||||
- Temporary credentials are displayed on the browser upon successful retrieval.
|
- Temporary credentials are displayed on the browser upon successful retrieval.
|
||||||
|
|
||||||
## Using MinIO Console
|
## Using MinIO Console
|
||||||
|
@ -64,19 +64,20 @@ def callback():
|
|||||||
|
|
||||||
data = {'grant_type': 'authorization_code',
|
data = {'grant_type': 'authorization_code',
|
||||||
'code': authorization_code, 'redirect_uri': callback_uri}
|
'code': authorization_code, 'redirect_uri': callback_uri}
|
||||||
access_token_response = requests.post(
|
id_token_response = requests.post(
|
||||||
token_url, data=data, verify=False, allow_redirects=False, auth=(client_id, client_secret))
|
token_url, data=data, verify=False,
|
||||||
|
allow_redirects=False, auth=(client_id, client_secret))
|
||||||
|
|
||||||
print('body: ' + access_token_response.text)
|
print('body: ' + id_token_response.text)
|
||||||
|
|
||||||
# we can now use the access_token as much as we want to access protected resources.
|
# we can now use the id_token as much as we want to access protected resources.
|
||||||
tokens = json.loads(access_token_response.text)
|
tokens = json.loads(id_token_response.text)
|
||||||
access_token = tokens['access_token']
|
id_token = tokens['id_token']
|
||||||
|
|
||||||
response = sts_client.assume_role_with_web_identity(
|
response = sts_client.assume_role_with_web_identity(
|
||||||
RoleArn='arn:aws:iam::123456789012:user/svc-internal-api',
|
RoleArn='arn:aws:iam::123456789012:user/svc-internal-api',
|
||||||
RoleSessionName='test',
|
RoleSessionName='test',
|
||||||
WebIdentityToken=access_token,
|
WebIdentityToken=id_token,
|
||||||
DurationSeconds=3600
|
DurationSeconds=3600
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ curl -u PoEgXP6uVO45IsENRngDXj5Au5Ya:eKsw6z8CtOJVBtrOWvhRWL4TUCga -k -d "grant_t
|
|||||||
In response, the self-contained JWT access token will be returned as shown below.
|
In response, the self-contained JWT access token will be returned as shown below.
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
"access_token": "eyJ4NXQiOiJOVEF4Wm1NeE5ETXlaRGczTVRVMVpHTTBNekV6T0RKaFpXSTRORE5sWkRVMU9HRmtOakZpTVEiLCJraWQiOiJOVEF4Wm1NeE5ETXlaRGczTVRVMVpHTTBNekV6T0RKaFpXSTRORE5sWkRVMU9HRmtOakZpTVEiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJQb0VnWFA2dVZPNDVJc0VOUm5nRFhqNUF1NVlhIiwiYXpwIjoiUG9FZ1hQNnVWTzQ1SXNFTlJuZ0RYajVBdTVZYSIsImlzcyI6Imh0dHBzOlwvXC9sb2NhbGhvc3Q6OTQ0M1wvb2F1dGgyXC90b2tlbiIsImV4cCI6MTUzNDg5MTc3OCwiaWF0IjoxNTM0ODg4MTc4LCJqdGkiOiIxODQ0MzI5Yy1kNjVhLTQ4YTMtODIyOC05ZGY3M2ZlODNkNTYifQ.ELZ8ujk2Xp9xTGgMqnCa5ehuimaAPXWlSCW5QeBbTJIT4M5OB_2XEVIV6p89kftjUdKu50oiYe4SbfrxmLm6NGSGd2qxkjzJK3SRKqsrmVWEn19juj8fz1neKtUdXVHuSZu6ws_bMDy4f_9hN2Jv9dFnkoyeNT54r4jSTJ4A2FzN2rkiURheVVsc8qlm8O7g64Az-5h4UGryyXU4zsnjDCBKYk9jdbEpcUskrFMYhuUlj1RWSASiGhHHHDU5dTRqHkVLIItfG48k_fb-ehU60T7EFWH1JBdNjOxM9oN_yb0hGwOjLUyCUJO_Y7xcd5F4dZzrBg8LffFmvJ09wzHNtQ",
|
"id_token": "eyJ4NXQiOiJOVEF4Wm1NeE5ETXlaRGczTVRVMVpHTTBNekV6T0RKaFpXSTRORE5sWkRVMU9HRmtOakZpTVEiLCJraWQiOiJOVEF4Wm1NeE5ETXlaRGczTVRVMVpHTTBNekV6T0RKaFpXSTRORE5sWkRVMU9HRmtOakZpTVEiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJQb0VnWFA2dVZPNDVJc0VOUm5nRFhqNUF1NVlhIiwiYXpwIjoiUG9FZ1hQNnVWTzQ1SXNFTlJuZ0RYajVBdTVZYSIsImlzcyI6Imh0dHBzOlwvXC9sb2NhbGhvc3Q6OTQ0M1wvb2F1dGgyXC90b2tlbiIsImV4cCI6MTUzNDg5MTc3OCwiaWF0IjoxNTM0ODg4MTc4LCJqdGkiOiIxODQ0MzI5Yy1kNjVhLTQ4YTMtODIyOC05ZGY3M2ZlODNkNTYifQ.ELZ8ujk2Xp9xTGgMqnCa5ehuimaAPXWlSCW5QeBbTJIT4M5OB_2XEVIV6p89kftjUdKu50oiYe4SbfrxmLm6NGSGd2qxkjzJK3SRKqsrmVWEn19juj8fz1neKtUdXVHuSZu6ws_bMDy4f_9hN2Jv9dFnkoyeNT54r4jSTJ4A2FzN2rkiURheVVsc8qlm8O7g64Az-5h4UGryyXU4zsnjDCBKYk9jdbEpcUskrFMYhuUlj1RWSASiGhHHHDU5dTRqHkVLIItfG48k_fb-ehU60T7EFWH1JBdNjOxM9oN_yb0hGwOjLUyCUJO_Y7xcd5F4dZzrBg8LffFmvJ09wzHNtQ",
|
||||||
"token_type": "Bearer",
|
"token_type": "Bearer",
|
||||||
"expires_in": 3600
|
"expires_in": 3600
|
||||||
}
|
}
|
||||||
@ -52,17 +52,17 @@ In response, the self-contained JWT access token will be returned as shown below
|
|||||||
### 4. JWT Claims
|
### 4. JWT Claims
|
||||||
The access token received is a signed JSON Web Token (JWT). Use a JWT decoder to decode the access token to access the payload of the token that includes following JWT claims:
|
The access token received is a signed JSON Web Token (JWT). Use a JWT decoder to decode the access token to access the payload of the token that includes following JWT claims:
|
||||||
|
|
||||||
|Claim Name|Type|Claim Value|
|
| Claim Name | Type | Claim Value |
|
||||||
|:--:|:--:|:--:|
|
|:----------:|:--------------:|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|
|
||||||
|iss| _string_ | The issuer of the JWT. The '> Identity Provider Entity Id ' value of the OAuth2/OpenID Connect Inbound Authentication configuration of the Resident Identity Provider is returned here. |
|
| iss | _string_ | The issuer of the JWT. The '> Identity Provider Entity Id ' value of the OAuth2/OpenID Connect Inbound Authentication configuration of the Resident Identity Provider is returned here. |
|
||||||
|aud| _string array_ | The token audience list. The client identifier of the OAuth clients that the JWT is intended for, is sent herewith. |
|
| aud | _string array_ | The token audience list. The client identifier of the OAuth clients that the JWT is intended for, is sent herewith. |
|
||||||
|azp| _string_ | The authorized party for which the token is issued to. The client identifier of the OAuth client that the token is issued for, is sent herewith. |
|
| azp | _string_ | The authorized party for which the token is issued to. The client identifier of the OAuth client that the token is issued for, is sent herewith. |
|
||||||
|iat| _integer_ | The token issue time. |
|
| iat | _integer_ | The token issue time. |
|
||||||
|exp| _integer_ | The token expiration time. |
|
| exp | _integer_ | The token expiration time. |
|
||||||
|jti| _string_ | Unique identifier for the JWT token. |
|
| jti | _string_ | Unique identifier for the JWT token. |
|
||||||
|policy| _string_ | Canned policy name to be applied for STS credentials. (Recommended) |
|
| policy | _string_ | Canned policy name to be applied for STS credentials. (Recommended) |
|
||||||
|
|
||||||
Using the above `access_token` we can perform an STS request to MinIO to get temporary credentials for MinIO API operations. MinIO STS API uses [JSON Web Key Set Endpoint](https://docs.wso2.com/display/IS541/JSON+Web+Key+Set+Endpoint) to validate if JWT is valid and is properly signed.
|
Using the above `id_token` we can perform an STS request to MinIO to get temporary credentials for MinIO API operations. MinIO STS API uses [JSON Web Key Set Endpoint](https://docs.wso2.com/display/IS541/JSON+Web+Key+Set+Endpoint) to validate if JWT is valid and is properly signed.
|
||||||
|
|
||||||
**We recommend setting `policy` as a custom claim for the JWT service provider follow [here](https://docs.wso2.com/display/IS550/Configuring+Claims+for+a+Service+Provider) and [here](https://docs.wso2.com/display/IS550/Handling+Custom+Claims+with+the+JWT+Bearer+Grant+Type) for relevant docs on how to configure claims for a service provider.**
|
**We recommend setting `policy` as a custom claim for the JWT service provider follow [here](https://docs.wso2.com/display/IS550/Configuring+Claims+for+a+Service+Provider) and [here](https://docs.wso2.com/display/IS550/Handling+Custom+Claims+with+the+JWT+Bearer+Grant+Type) for relevant docs on how to configure claims for a service provider.**
|
||||||
|
|
||||||
|
2
go.mod
2
go.mod
@ -48,7 +48,7 @@ require (
|
|||||||
github.com/minio/madmin-go v1.0.19
|
github.com/minio/madmin-go v1.0.19
|
||||||
github.com/minio/minio-go/v7 v7.0.13-0.20210715203016-9e713532886e
|
github.com/minio/minio-go/v7 v7.0.13-0.20210715203016-9e713532886e
|
||||||
github.com/minio/parquet-go v1.0.0
|
github.com/minio/parquet-go v1.0.0
|
||||||
github.com/minio/pkg v1.0.10
|
github.com/minio/pkg v1.0.11
|
||||||
github.com/minio/selfupdate v0.3.1
|
github.com/minio/selfupdate v0.3.1
|
||||||
github.com/minio/sha256-simd v1.0.0
|
github.com/minio/sha256-simd v1.0.0
|
||||||
github.com/minio/simdjson-go v0.2.1
|
github.com/minio/simdjson-go v0.2.1
|
||||||
|
4
go.sum
4
go.sum
@ -1045,8 +1045,8 @@ github.com/minio/parquet-go v1.0.0/go.mod h1:aQlkSOfOq2AtQKkuou3mosNVMwNokd+faTa
|
|||||||
github.com/minio/pkg v1.0.3/go.mod h1:obU54TZ9QlMv0TRaDgQ/JTzf11ZSXxnSfLrm4tMtBP8=
|
github.com/minio/pkg v1.0.3/go.mod h1:obU54TZ9QlMv0TRaDgQ/JTzf11ZSXxnSfLrm4tMtBP8=
|
||||||
github.com/minio/pkg v1.0.4/go.mod h1:obU54TZ9QlMv0TRaDgQ/JTzf11ZSXxnSfLrm4tMtBP8=
|
github.com/minio/pkg v1.0.4/go.mod h1:obU54TZ9QlMv0TRaDgQ/JTzf11ZSXxnSfLrm4tMtBP8=
|
||||||
github.com/minio/pkg v1.0.8/go.mod h1:32x/3OmGB0EOi1N+3ggnp+B5VFkSBBB9svPMVfpnf14=
|
github.com/minio/pkg v1.0.8/go.mod h1:32x/3OmGB0EOi1N+3ggnp+B5VFkSBBB9svPMVfpnf14=
|
||||||
github.com/minio/pkg v1.0.10 h1:fohpAm/0ttQFf4BzmzH5r6A9JUIfg63AyGCPM0f9/9U=
|
github.com/minio/pkg v1.0.11 h1:gfpkP7SiznM7EyyHIfQ7lu98Ae4hV4Z+8YsoFQbH7PY=
|
||||||
github.com/minio/pkg v1.0.10/go.mod h1:32x/3OmGB0EOi1N+3ggnp+B5VFkSBBB9svPMVfpnf14=
|
github.com/minio/pkg v1.0.11/go.mod h1:32x/3OmGB0EOi1N+3ggnp+B5VFkSBBB9svPMVfpnf14=
|
||||||
github.com/minio/selfupdate v0.3.1 h1:BWEFSNnrZVMUWXbXIgLDNDjbejkmpAmZvy/nCz1HlEs=
|
github.com/minio/selfupdate v0.3.1 h1:BWEFSNnrZVMUWXbXIgLDNDjbejkmpAmZvy/nCz1HlEs=
|
||||||
github.com/minio/selfupdate v0.3.1/go.mod h1:b8ThJzzH7u2MkF6PcIra7KaXO9Khf6alWPvMSyTDCFM=
|
github.com/minio/selfupdate v0.3.1/go.mod h1:b8ThJzzH7u2MkF6PcIra7KaXO9Khf6alWPvMSyTDCFM=
|
||||||
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
||||||
|
Loading…
x
Reference in New Issue
Block a user