diff --git a/path_oidc.go b/path_oidc.go index dde0484b..24e46d9a 100644 --- a/path_oidc.go +++ b/path_oidc.go @@ -305,6 +305,23 @@ func (b *jwtAuthBackend) pathCallback(ctx context.Context, req *logical.Request, } } + // Also fetch any requested extra oauth2 metadata + oauth2Metadata := make(map[string]string) + for _, mdname := range role.Oauth2Metadata { + var md string + switch mdname { + case "id_token": + md = string(token.IDToken()) + case "refresh_token": + md = string(token.RefreshToken()) + case "access_token": + md = string(token.AccessToken()) + default: + return logical.ErrorResponse(errLoginFailed + " Unrecognized oauth2 metadata name " + mdname), nil + } + oauth2Metadata[mdname] = md + } + if role.VerboseOIDCLogging { if c, err := json.Marshal(allClaims); err == nil { b.Logger().Debug("OIDC provider response", "claims", string(c)) @@ -326,6 +343,9 @@ func (b *jwtAuthBackend) pathCallback(ctx context.Context, req *logical.Request, for k, v := range alias.Metadata { tokenMetadata[k] = v } + for k, v := range oauth2Metadata { + tokenMetadata["oauth2_" + k] = v + } auth := &logical.Auth{ Policies: role.Policies, diff --git a/path_oidc_test.go b/path_oidc_test.go index 28772261..75119bf4 100644 --- a/path_oidc_test.go +++ b/path_oidc_test.go @@ -815,8 +815,17 @@ func TestOIDC_Callback(t *testing.T) { auth := resp.Auth + if auth != nil { + // Can't predict the content of oauth2_id_token + // so instead copy it. This does at least + // verify that it is present because if not it + // introduces an empty value into expected. + expected.Metadata["oauth2_id_token"] = + auth.Metadata["oauth2_id_token"] + } + if !reflect.DeepEqual(auth, expected) { - t.Fatalf("expected: %v, auth: %v", expected, resp) + t.Fatalf("expected: %v, resp: %v", expected, resp) } } }) @@ -1588,6 +1597,7 @@ func getBackendAndServer(t *testing.T, boundCIDRs bool) (logical.Backend, logica "/nested/secret_code": "bar", "temperature": "76", }, + "oauth2_metadata": []string{"id_token"}, } if boundCIDRs { diff --git a/path_role.go b/path_role.go index f94c03cf..a6b68045 100644 --- a/path_role.go +++ b/path_role.go @@ -133,6 +133,10 @@ Defaults to 60 (1 minute) if set to 0 and can be disabled if set to -1.`, Type: framework.TypeKVPairs, Description: `Mappings of claims (key) that will be copied to a metadata field (value)`, }, + "oauth2_metadata": { + Type: framework.TypeCommaStringSlice, + Description: `Comma-separated list of one or more of access_token, id_token, refresh_token to return in metadata`, + }, "user_claim": { Type: framework.TypeString, Description: `The claim to use for the Identity entity alias name`, @@ -218,6 +222,7 @@ type jwtRole struct { BoundClaimsType string `json:"bound_claims_type"` BoundClaims map[string]interface{} `json:"bound_claims"` ClaimMappings map[string]string `json:"claim_mappings"` + Oauth2Metadata []string `json:"oauth2_metadata"` UserClaim string `json:"user_claim"` GroupsClaim string `json:"groups_claim"` OIDCScopes []string `json:"oidc_scopes"` @@ -326,6 +331,7 @@ func (b *jwtAuthBackend) pathRoleRead(ctx context.Context, req *logical.Request, "bound_claims_type": role.BoundClaimsType, "bound_claims": role.BoundClaims, "claim_mappings": role.ClaimMappings, + "oauth2_metadata": role.Oauth2Metadata, "user_claim": role.UserClaim, "user_claim_json_pointer": role.UserClaimJSONPointer, "groups_claim": role.GroupsClaim, @@ -518,6 +524,10 @@ func (b *jwtAuthBackend) pathRoleCreateUpdate(ctx context.Context, req *logical. role.ClaimMappings = claimMappings } + if oauth2Metadata, ok := data.GetOk("oauth2_metadata"); ok { + role.Oauth2Metadata = oauth2Metadata.([]string) + } + if userClaim, ok := data.GetOk("user_claim"); ok { role.UserClaim = userClaim.(string) } diff --git a/path_role_test.go b/path_role_test.go index 5628433f..5e7158af 100644 --- a/path_role_test.go +++ b/path_role_test.go @@ -767,6 +767,7 @@ func TestPath_Read(t *testing.T) { "bound_claims_type": "string", "bound_claims": map[string]interface{}(nil), "claim_mappings": map[string]string(nil), + "oauth2_metadata": []string(nil), "bound_subject": "testsub", "bound_audiences": []string{"vault"}, "allowed_redirect_uris": []string{"http://127.0.0.1"},