-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgranttype_exchange.go
146 lines (133 loc) · 4.54 KB
/
granttype_exchange.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package oidc
import (
"context"
"crypto/sha256"
"fmt"
"github.com/go-jose/go-jose/v3"
"github.com/xslasd/x-oidc/constant"
"github.com/xslasd/x-oidc/ecode"
"github.com/xslasd/x-oidc/storage"
"github.com/xslasd/x-oidc/util"
"net/http"
"net/url"
"strings"
)
type OAuthClientReq struct {
ClientID string `json:"client_id" form:"client_id"`
ClientSecret string `json:"client_secret" form:"client_secret"`
ClientAssertion string `json:"client_assertion" form:"client_assertion"`
ClientAssertionType string `json:"client_assertion_type" form:"client_assertion_type"`
}
type TokenExchangeReq struct {
*OAuthClientReq
GrantType string `json:"grant_type" form:"grant_type"`
//GrantTypeCode
Code string `json:"code" form:"code"`
RedirectURI string `json:"redirect_uri" form:"redirect_uri"`
CodeVerifier string `json:"code_verifier" form:"code_verifier"`
//GrantTypeRefreshToken
RefreshToken string `json:"refresh_token" form:"refresh_token"`
Scopes string `json:"scope" form:"scope"` //SpaceDelimitedArray
//GrantTypeJwtBearer
Assertion string `json:"assertion" form:"assertion"`
//GrantTypeTokenExchange
SubjectToken string `json:"subject_token" form:"subject_token"`
SubjectTokenType string `json:"subject_token_type" form:"subject_token_type"`
ActorToken string `json:"actor_token" form:"actor_token"`
ActorTokenType string `json:"actor_token_type" form:"actor_token_type"`
Resource string `json:"resource" form:"resource"` //SpaceDelimitedArray
Audience string `json:"audience" form:"audience"` //SpaceDelimitedArray
RequestedTokenType string `json:"requested_token_type" form:"requested_token_type"`
//Scopes string `json:"scope" form:"scope"` //SpaceDelimitedArray
}
func (t *TokenExchangeReq) unmarshalScopes() []string {
return strings.Split(t.Scopes, " ")
}
func (o *OpenIDProvider) tokenExchange(ctx context.Context, req *TokenExchangeReq, r *http.Request) (interface{}, error) {
switch req.GrantType {
case constant.GrantTypeCode:
err := parseAuthenticatedBasicAuth(req.OAuthClientReq, r)
if err != nil {
}
return o.codeExchange(ctx, req)
case constant.GrantTypeRefreshToken:
err := parseAuthenticatedBasicAuth(req.OAuthClientReq, r)
if err != nil {
}
return o.refreshTokenExchange(ctx, req)
case constant.GrantTypeJwtBearer:
return o.jwtBearerExchange(ctx, req)
case constant.GrantTypeTokenExchange:
err := parseAuthenticatedBasicAuth(req.OAuthClientReq, r)
if err != nil {
}
return o.subjectTokenExchange(ctx, req)
case constant.GrantTypeClientCredentials:
err := parseAuthenticatedBasicAuth(req.OAuthClientReq, r)
if err != nil {
}
return o.clientCredentialsExchange(ctx, req)
case constant.GrantTypeDeviceCode:
return o.deviceCodeExchange(ctx, req)
case constant.GrantTypeImplicit:
}
return nil, ecode.UnauthorizedClientGrantType.SetDescriptionf(req.GrantType)
}
func parseAuthenticatedBasicAuth(req *OAuthClientReq, r *http.Request) error {
var err error
if req.ClientID == "" || req.ClientSecret == "" {
clientID, clientSecret, ok := r.BasicAuth()
if ok {
clientID, err = url.QueryUnescape(clientID)
if err != nil {
return err
}
clientSecret, err = url.QueryUnescape(clientSecret)
if err != nil {
return err
}
req.ClientID = clientID
req.ClientSecret = clientSecret
}
}
return err
}
func authenticatedClient(req *OAuthClientReq, client storage.IClient) error {
switch client.AuthMethod() {
case constant.AuthMethodPrivateKeyJWT:
if req.ClientAssertionType == constant.ClientAssertionTypeJWTAssertion {
jws, err := jose.ParseSigned(req.ClientAssertion)
if err != nil {
return err
}
_, err = jws.Verify(client.JoseVerificationKey(constant.ClientAssertion))
if err != nil {
return err
}
}
case constant.AuthMethodBasic, constant.AuthMethodPost:
if client.GetClientSecret() != req.ClientSecret {
return ecode.ClientIDOrSecretInvalid
}
default:
}
return nil
}
// authorizeCodeChallenge authorizes a client by validating the code_verifier against the previously sent
func authorizeCodeChallenge(req *TokenExchangeReq, authReq *storage.AuthRequest) error {
if authReq.CodeChallenge == "" {
return nil
}
if req.CodeVerifier == "" {
return ecode.CodeChallengeInvalid
}
switch authReq.CodeChallengeMethod {
case constant.CodeChallengeMethodS256:
req.CodeVerifier = util.HashString(sha256.New(), req.CodeVerifier, false)
}
if req.CodeVerifier != authReq.CodeChallenge {
fmt.Println("debug: CodeChallengeInvalid")
return ecode.CodeChallengeInvalid
}
return nil
}