-
Notifications
You must be signed in to change notification settings - Fork 1
/
steranko_.go
97 lines (71 loc) · 2.94 KB
/
steranko_.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
package steranko
import (
"net/http"
"github.com/benpate/derp"
"github.com/benpate/rosetta/schema"
"github.com/golang-jwt/jwt/v5"
)
// Steranko contains all required configuration information for this library.
type Steranko struct {
userService UserService // Service that provides CRUD operations on Users
keyService KeyService // Service that generates/retrieves encryption keys used in JWT signatures.
passwordSchema schema.Schema // Validating schema to use when setting new passwords.
passwordRules []PasswordRule // PasswordRules are additional validators that are applied to new passwords.
passwordHashers []PasswordHasher // PasswordHashers is a list of one-way encryption hashes that stored passwords.
}
// New returns a fully initialized Steranko instance, with HandlerFuncs that support all of your user authentication and authorization needs.
func New(userService UserService, keyService KeyService, options ...Option) *Steranko {
result := Steranko{
userService: userService,
keyService: keyService,
passwordHashers: []PasswordHasher{defaultPasswordHasher()}, // hash.Plaintext{},
passwordSchema: schema.New(schema.String{MinLength: 8, Required: true}),
}
result.WithOptions(options...)
return &result
}
// WithOptios applies the provided Option functions to this Steranko instance.
func (s *Steranko) WithOptions(options ...Option) {
for _, option := range options {
option(s)
}
}
// GetAuthorization retrieves the JWT token claims from the request.
func (s *Steranko) GetAuthorization(request *http.Request) (jwt.Claims, error) {
// Retrieve the cookie value from the context
cookieName := cookieName(request)
cookie, err := request.Cookie(cookieName)
if err != nil {
return nil, derp.Wrap(err, "", "Invalid cookie")
}
return s.GetAuthorizationFromToken(cookie.Value)
}
// GetAuthorizationFromToken parses a JWT token
func (s *Steranko) GetAuthorizationFromToken(tokenString string) (jwt.Claims, error) {
const location = "steranko.Context.GetAuthorizationFromToken"
claims := s.userService.NewClaims()
// Parse it as a JWT token
token, err := jwt.ParseWithClaims(tokenString, claims, s.keyService.FindJWTKey, jwt.WithValidMethods([]string{"HS256", "HS384", "HS512"}))
if err != nil {
return nil, derp.Wrap(err, location, "Error parsing token")
}
if !token.Valid {
return nil, derp.NewForbiddenError(location, "Token is invalid")
}
return claims, nil
}
func (s *Steranko) SetPassword(user User, plaintext string) error {
hashedValue, err := s.PrimaryPasswordHasher().HashPassword(plaintext)
if err != nil {
return derp.Wrap(err, "steranko.SetPassword", "Error hashing password")
}
user.SetPassword(hashedValue)
return nil
}
/******************************************
* Utility Methods
******************************************/
// PasswordSchema returns the schema.Schema for validating passwords
func (s *Steranko) PasswordSchema() *schema.Schema {
return &s.passwordSchema
}