/
mw_oauth2_key_exists.go
134 lines (108 loc) · 4 KB
/
mw_oauth2_key_exists.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
package gateway
import (
"net/http"
"strings"
"time"
"github.com/TykTechnologies/tyk/config"
"github.com/TykTechnologies/tyk/apidef"
)
const (
checkOAuthClientDeletedInetrval = 1 * time.Second
)
const (
ErrOAuthAuthorizationFieldMissing = "oauth.auth_field_missing"
ErrOAuthAuthorizationFieldMalformed = "oauth.auth_field_malformed"
ErrOAuthKeyNotFound = "oauth.key_not_found"
ErrOAuthClientDeleted = "oauth.client_deleted"
)
func init() {
TykErrors[ErrOAuthAuthorizationFieldMissing] = config.TykError{
Message: "Authorization field missing",
Code: http.StatusBadRequest,
}
TykErrors[ErrOAuthAuthorizationFieldMalformed] = config.TykError{
Message: "Bearer token malformed",
Code: http.StatusBadRequest,
}
TykErrors[ErrOAuthKeyNotFound] = config.TykError{
Message: "Key not authorised",
Code: http.StatusForbidden,
}
TykErrors[ErrOAuthClientDeleted] = config.TykError{
Message: "Key not authorised. OAuth client access was revoked",
Code: http.StatusForbidden,
}
}
// Oauth2KeyExists will check if the key being used to access the API is in the request data,
// and then if the key is in the storage engine
type Oauth2KeyExists struct {
BaseMiddleware
}
func (k *Oauth2KeyExists) Name() string {
return "Oauth2KeyExists"
}
func (k *Oauth2KeyExists) EnabledForSpec() bool {
return k.Spec.UseOauth2
}
// getAuthType overrides BaseMiddleware.getAuthType.
func (k *Oauth2KeyExists) getAuthType() string {
return oauthType
}
// ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail
func (k *Oauth2KeyExists) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
if ctxGetRequestStatus(r) == StatusOkAndIgnore {
return nil, http.StatusOK
}
logger := k.Logger()
// We're using OAuth, start checking for access keys
token, _ := k.getAuthToken(k.getAuthType(), r)
parts := strings.Split(token, " ")
if len(parts) < 2 {
logger.Info("Attempted access with malformed header, no auth header found.")
return errorAndStatusCode(ErrOAuthAuthorizationFieldMissing)
}
if strings.ToLower(parts[0]) != "bearer" {
logger.Info("Bearer token malformed")
return errorAndStatusCode(ErrOAuthAuthorizationFieldMalformed)
}
accessToken := parts[1]
logger = logger.WithField("key", obfuscateKey(accessToken))
// get session for the given oauth token
session, keyExists := k.CheckSessionAndIdentityForValidKey(accessToken, r)
if !keyExists {
logger.Warning("Attempted access with non-existent key.")
// Fire Authfailed Event
AuthFailed(k, r, accessToken)
// Report in health check
reportHealthValue(k.Spec, KeyFailure, "-1")
return errorAndStatusCode(ErrOAuthKeyNotFound)
}
// Make sure OAuth-client is still present
oauthClientDeletedKey := "oauth-del-" + k.Spec.APIID + session.OauthClientID
oauthClientDeleted := false
// check if that oauth client was deleted with using memory cache first
if val, found := UtilCache.Get(oauthClientDeletedKey); found {
oauthClientDeleted = val.(bool)
} else {
// if not cached in memory then hit Redis to get oauth-client from there
if _, err := k.Spec.OAuthManager.OsinServer.Storage.GetClient(session.OauthClientID); err != nil {
// set this oauth client as deleted in memory cache for the next N sec
UtilCache.Set(oauthClientDeletedKey, true, checkOAuthClientDeletedInetrval)
oauthClientDeleted = true
} else {
// set this oauth client as NOT deleted in memory cache for next N sec
UtilCache.Set(oauthClientDeletedKey, false, checkOAuthClientDeletedInetrval)
}
}
if oauthClientDeleted {
logger.WithField("oauthClientID", session.OauthClientID).Warning("Attempted access for deleted OAuth client.")
return errorAndStatusCode(ErrOAuthClientDeleted)
}
// Set session state on context, we will need it later
switch k.Spec.BaseIdentityProvidedBy {
case apidef.OAuthKey, apidef.UnsetAuth:
ctxSetSession(r, &session, accessToken, false)
}
// Request is valid, carry on
return nil, http.StatusOK
}