forked from libopenstorage/openstorage
/
selfsigned.go
154 lines (131 loc) · 4.39 KB
/
selfsigned.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
147
148
149
150
151
152
153
154
/*
Copyright 2019 Portworx
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package auth
import (
"context"
"encoding/json"
"fmt"
"strings"
jwt "github.com/dgrijalva/jwt-go"
)
// JwtAuthConfig provides JwtAuthenticator the keys to validate the token
type JwtAuthConfig struct {
// SharedSecret in byte array form
SharedSecret []byte
// RsaPublicPem is the contents of the RSA public key file
RsaPublicPem []byte
// ECDSPublicPem is the contents of the ECDS public key file
ECDSPublicPem []byte
// UsernameClaim has the location of the unique id for the user.
// If empty, "sub" will be used for the user name unique id.
UsernameClaim UsernameClaimType
}
// JwtAuthenticator definition. It contains the raw bytes of the keys and their
// objects as returned by the Jwt package
type JwtAuthenticator struct {
config JwtAuthConfig
rsaKey interface{}
ecdsKey interface{}
sharedSecretKey interface{}
usernameClaim UsernameClaimType
}
// New returns a JwtAuthenticator
func NewJwtAuth(config *JwtAuthConfig) (*JwtAuthenticator, error) {
if config == nil {
return nil, fmt.Errorf("Must provide configuration")
}
// Check at least one is set
if len(config.SharedSecret) == 0 &&
len(config.RsaPublicPem) == 0 &&
len(config.ECDSPublicPem) == 0 {
return nil, fmt.Errorf("Server was passed empty authentication information with no shared secret or pem files set")
}
authenticator := &JwtAuthenticator{
config: *config,
usernameClaim: config.UsernameClaim,
}
var err error
if len(config.SharedSecret) != 0 {
authenticator.sharedSecretKey = config.SharedSecret
}
if len(config.RsaPublicPem) != 0 {
authenticator.rsaKey, err = jwt.ParseRSAPublicKeyFromPEM(config.RsaPublicPem)
if err != nil {
return nil, fmt.Errorf("Unable to parse rsa public key: %v", err)
}
}
if len(config.ECDSPublicPem) != 0 {
authenticator.ecdsKey, err = jwt.ParseECPublicKeyFromPEM(config.ECDSPublicPem)
if err != nil {
return nil, fmt.Errorf("Unable to parse ecds public key: %v", err)
}
}
return authenticator, nil
}
// AuthenticateToken determines if a token is valid and if it is, returns
// the information in the claims.
func (j *JwtAuthenticator) AuthenticateToken(ctx context.Context, rawtoken string) (*Claims, error) {
// Parse token
token, err := jwt.Parse(rawtoken, func(token *jwt.Token) (interface{}, error) {
// Verify Method
if strings.HasPrefix(token.Method.Alg(), "RS") {
// RS256, RS384, or RS512
return j.rsaKey, nil
} else if strings.HasPrefix(token.Method.Alg(), "ES") {
// ES256, ES384, or ES512
return j.ecdsKey, nil
} else if strings.HasPrefix(token.Method.Alg(), "HS") {
// HS256, HS384, or HS512
return j.sharedSecretKey, nil
}
return nil, fmt.Errorf("Unknown token algorithm: %s", token.Method.Alg())
})
if err != nil {
return nil, err
}
if !token.Valid {
return nil, fmt.Errorf("Token failed validation")
}
// Get claims
claims, ok := token.Claims.(jwt.MapClaims)
if claims == nil || !ok {
return nil, fmt.Errorf("No claims found in token")
}
// Check for required claims
for _, requiredClaim := range requiredClaims {
if _, ok := claims[requiredClaim]; !ok {
// Claim missing
return nil, fmt.Errorf("Required claim %v missing from token", requiredClaim)
}
}
// Token now has been verified.
// Claims holds all the authorization information.
// Here we need to first decode it then unmarshal it from JSON
parts := strings.Split(token.Raw, ".")
claimBytes, err := jwt.DecodeSegment(parts[1])
if err != nil {
return nil, fmt.Errorf("Failed to decode claims: %v", err)
}
var sdkClaims Claims
err = json.Unmarshal(claimBytes, &sdkClaims)
if err != nil {
return nil, fmt.Errorf("Unable to get sdkclaims: %v", err)
}
if err := validateUsername(j.usernameClaim, &sdkClaims); err != nil {
return nil, err
}
return &sdkClaims, nil
}
func (j *JwtAuthenticator) Username(claims *Claims) string {
return getUsername(j.usernameClaim, claims)
}