Source file
src/github.com/ory/fosite/introspection_request_handler.go
1
21
22 package fosite
23
24 import (
25 "context"
26 "net/http"
27 "net/url"
28 "strings"
29
30 "github.com/ory/x/errorsx"
31 "golang.org/x/text/language"
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 func (f *Fosite) NewIntrospectionRequest(ctx context.Context, r *http.Request, session Session) (IntrospectionResponder, error) {
114 ctx = context.WithValue(ctx, RequestContextKey, r)
115
116 if r.Method != "POST" {
117 return &IntrospectionResponse{Active: false}, errorsx.WithStack(ErrInvalidRequest.WithHintf("HTTP method is '%s' but expected 'POST'.", r.Method))
118 } else if err := r.ParseMultipartForm(1 << 20); err != nil && err != http.ErrNotMultipart {
119 return &IntrospectionResponse{Active: false}, errorsx.WithStack(ErrInvalidRequest.WithHint("Unable to parse HTTP body, make sure to send a properly formatted form request body.").WithWrap(err).WithDebug(err.Error()))
120 } else if len(r.PostForm) == 0 {
121 return &IntrospectionResponse{Active: false}, errorsx.WithStack(ErrInvalidRequest.WithHint("The POST body can not be empty."))
122 }
123
124 token := r.PostForm.Get("token")
125 tokenTypeHint := r.PostForm.Get("token_type_hint")
126 scope := r.PostForm.Get("scope")
127 if clientToken := AccessTokenFromRequest(r); clientToken != "" {
128 if token == clientToken {
129 return &IntrospectionResponse{Active: false}, errorsx.WithStack(ErrRequestUnauthorized.WithHint("Bearer and introspection token are identical."))
130 }
131
132 if tu, _, err := f.IntrospectToken(ctx, clientToken, AccessToken, session.Clone()); err != nil {
133 return &IntrospectionResponse{Active: false}, errorsx.WithStack(ErrRequestUnauthorized.WithHint("HTTP Authorization header missing, malformed, or credentials used are invalid."))
134 } else if tu != "" && tu != AccessToken {
135 return &IntrospectionResponse{Active: false}, errorsx.WithStack(ErrRequestUnauthorized.WithHintf("HTTP Authorization header did not provide a token of type 'access_token', got type '%s'.", tu))
136 }
137 } else {
138 id, secret, ok := r.BasicAuth()
139 if !ok {
140 return &IntrospectionResponse{Active: false}, errorsx.WithStack(ErrRequestUnauthorized.WithHint("HTTP Authorization header missing."))
141 }
142
143 clientID, err := url.QueryUnescape(id)
144 if err != nil {
145 return &IntrospectionResponse{Active: false}, errorsx.WithStack(ErrRequestUnauthorized.WithHint("Unable to decode OAuth 2.0 Client ID from HTTP basic authorization header, make sure it is properly encoded.").WithWrap(err).WithDebug(err.Error()))
146 }
147
148 clientSecret, err := url.QueryUnescape(secret)
149 if err != nil {
150 return &IntrospectionResponse{Active: false}, errorsx.WithStack(ErrRequestUnauthorized.WithHint("Unable to decode OAuth 2.0 Client Secret from HTTP basic authorization header, make sure it is properly encoded.").WithWrap(err).WithDebug(err.Error()))
151 }
152
153 client, err := f.Store.GetClient(ctx, clientID)
154 if err != nil {
155 return &IntrospectionResponse{Active: false}, errorsx.WithStack(ErrRequestUnauthorized.WithHint("Unable to find OAuth 2.0 Client from HTTP basic authorization header.").WithWrap(err).WithDebug(err.Error()))
156 }
157
158
159 if err := f.checkClientSecret(ctx, client, []byte(clientSecret)); err != nil {
160 return &IntrospectionResponse{Active: false}, errorsx.WithStack(ErrRequestUnauthorized.WithHint("OAuth 2.0 Client credentials are invalid."))
161 }
162 }
163
164 tu, ar, err := f.IntrospectToken(ctx, token, TokenUse(tokenTypeHint), session, RemoveEmpty(strings.Split(scope, " "))...)
165 if err != nil {
166 return &IntrospectionResponse{Active: false}, errorsx.WithStack(ErrInactiveToken.WithHint("An introspection strategy indicated that the token is inactive.").WithWrap(err).WithDebug(err.Error()))
167 }
168 accessTokenType := ""
169
170 if tu == AccessToken {
171 accessTokenType = BearerAccessToken
172 }
173
174 return &IntrospectionResponse{
175 Active: true,
176 AccessRequester: ar,
177 TokenUse: tu,
178 AccessTokenType: accessTokenType,
179 }, nil
180 }
181
182 type IntrospectionResponse struct {
183 Active bool `json:"active"`
184 AccessRequester AccessRequester `json:"extra"`
185 TokenUse TokenUse `json:"token_use,omitempty"`
186 AccessTokenType string `json:"token_type,omitempty"`
187 Lang language.Tag `json:"-"`
188 }
189
190 func (r *IntrospectionResponse) IsActive() bool {
191 return r.Active
192 }
193
194 func (r *IntrospectionResponse) GetAccessRequester() AccessRequester {
195 return r.AccessRequester
196 }
197
198 func (r *IntrospectionResponse) GetTokenUse() TokenUse {
199 return r.TokenUse
200 }
201
202 func (r *IntrospectionResponse) GetAccessTokenType() string {
203 return r.AccessTokenType
204 }
205
View as plain text