Skip to content

Commit de1d815

Browse files
idp-go-sdk: Refactor some stuff
1 parent 636b804 commit de1d815

5 files changed

Lines changed: 99 additions & 44 deletions

File tree

integrations/idp-go-sdk/idp/auth.go

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,91 @@ package idp
22

33
import (
44
"crypto/rsa"
5+
"encoding/json"
56

67
"github.com/OliverSchlueter/goutils/broker"
78
)
89

10+
var ServiceBaseURL = "https://fancyanalytics.net/idp/api/v1"
11+
12+
// Service provides methods to interact with the IDP service.
913
type Service struct {
1014
broker broker.Broker
1115
excludedRoutes []string
1216
publicKey *rsa.PublicKey
1317
usersCache *usersCache
1418
}
1519

20+
// Configuration holds the necessary configuration for initializing the IDP service.
1621
type Configuration struct {
17-
PublicKey *rsa.PublicKey
18-
Broker broker.Broker
22+
// Broker is the message broker used for communication with the IDP service.
23+
Broker broker.Broker
24+
25+
// PublicKey is the RSA public key used for validating JWT tokens issued by the IDP service.
26+
PublicKey *rsa.PublicKey
27+
28+
// ExcludedRoutes is a list of (HTTP) routes that should be excluded from authentication checks. (optional)
1929
ExcludedRoutes []string
2030
}
2131

32+
// NewService initializes and returns a new instance of the IDP service with the provided configuration.
2233
func NewService(cfg Configuration) *Service {
34+
if cfg.ExcludedRoutes == nil {
35+
cfg.ExcludedRoutes = []string{}
36+
}
37+
2338
return &Service{
2439
broker: cfg.Broker,
2540
excludedRoutes: cfg.ExcludedRoutes,
2641
publicKey: cfg.PublicKey,
2742
usersCache: newUsersCache(),
2843
}
2944
}
45+
46+
// GetUser retrieves a user by their ID or email.
47+
func (s *Service) GetUser(id string) (*User, error) {
48+
userFromCache, err := s.usersCache.GetByID(id)
49+
if err == nil {
50+
return userFromCache, nil
51+
}
52+
53+
resp, err := s.broker.Request("idp.user.get", []byte(id))
54+
if err != nil {
55+
return nil, err
56+
}
57+
58+
var u User
59+
if err := json.Unmarshal(resp.Data, &u); err != nil {
60+
return nil, err
61+
}
62+
63+
s.usersCache.UpsertUser(&u)
64+
65+
return &u, nil
66+
}
67+
68+
// ValidateUser validates a user's credentials and returns the user if valid.
69+
func (s *Service) ValidateUser(userID, password string) (*User, error) {
70+
userFromCache, err := s.usersCache.GetByID(userID)
71+
if err == nil {
72+
// user found in cache, validate password
73+
if userFromCache.Password != PasswordHash(password) {
74+
return nil, ErrInvalidBasicCredentials
75+
}
76+
return userFromCache, nil
77+
}
78+
79+
resp, err := s.broker.Request("idp.user.validate", []byte(`{"username":"`+userID+`", "password":"`+password+`"}`))
80+
if err != nil {
81+
return nil, err
82+
}
83+
84+
var u User
85+
if err := json.Unmarshal(resp.Data, &u); err != nil {
86+
return nil, err
87+
}
88+
89+
s.usersCache.UpsertUser(&u)
90+
91+
return &u, nil
92+
}

integrations/idp-go-sdk/idp/errors.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ var (
1212
ErrMissingAuthorizationHeader = errors.New("missing Authorization header")
1313
ErrInvalidTokenFormat = errors.New("invalid token format")
1414
ErrInvalidAuthenticationMethod = errors.New("invalid authentication method, expected Bearer or Basic")
15+
ErrInvalidBasicCredentials = errors.New("invalid basic authentication credentials")
1516
ErrInvalidToken = errors.New("invalid token")
1617
ErrUserNotFound = errors.New("user not found")
1718
)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package idp
2+
3+
import (
4+
"crypto/sha256"
5+
"fmt"
6+
)
7+
8+
func PasswordHash(password string) string {
9+
h := sha256.New()
10+
h.Write([]byte(password))
11+
bs := h.Sum(nil)
12+
return fmt.Sprintf("%x", bs)
13+
}

integrations/idp-go-sdk/idp/http.go

Lines changed: 8 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
package idp
22

33
import (
4-
"encoding/json"
54
"fmt"
65
"net/http"
76
"regexp"
87
"strings"
98
)
109

11-
func (s *Service) validateRequest(r *http.Request) (*User, error) {
10+
func (s *Service) validateHTTPRequest(r *http.Request) (*User, error) {
1211
if r.Header.Get("Authorization") == "" {
1312
return nil, ErrMissingAuthorizationHeader
1413
}
@@ -21,29 +20,11 @@ func (s *Service) validateRequest(r *http.Request) (*User, error) {
2120
return nil, err
2221
}
2322

24-
userID, err := s.validateToken(token)
23+
u, err := s.ValidateToken(token)
2524
if err != nil {
2625
return nil, fmt.Errorf("failed to validate token: %w", err)
2726
}
28-
29-
userFromCache, err := s.usersCache.GetByID(userID)
30-
if err == nil {
31-
return userFromCache, nil
32-
}
33-
34-
resp, err := s.broker.Request("idp.user.get", []byte(userID))
35-
if err != nil {
36-
return nil, fmt.Errorf("failed to get user data: %w", err)
37-
}
38-
39-
var u User
40-
if err := json.Unmarshal(resp.Data, &u); err != nil {
41-
return nil, fmt.Errorf("failed to unmarshal user data: %w", err)
42-
}
43-
44-
s.usersCache.UpsertUser(&u)
45-
46-
return &u, nil
27+
return u, nil
4728
}
4829

4930
if strings.HasPrefix(authValue, "Basic ") {
@@ -52,23 +33,18 @@ func (s *Service) validateRequest(r *http.Request) (*User, error) {
5233
return nil, err
5334
}
5435

55-
resp, err := s.broker.Request("idp.user.validate", []byte(fmt.Sprintf(`{"username":"%s", "password":"%s"}`, userid, password)))
36+
u, err := s.ValidateUser(userid, password)
5637
if err != nil {
57-
return nil, fmt.Errorf("failed to validate user: %w", err)
58-
}
59-
60-
var u User
61-
if err := json.Unmarshal(resp.Data, &u); err != nil {
62-
return nil, fmt.Errorf("failed to unmarshal user data: %w", err)
38+
return nil, fmt.Errorf("failed to validate basic credentials: %w", err)
6339
}
6440

65-
return &u, nil
41+
return u, nil
6642
}
6743

6844
return nil, ErrInvalidAuthenticationMethod
6945
}
7046

71-
func (s *Service) Middleware(next http.Handler) http.Handler {
47+
func (s *Service) HTTPMiddleware(next http.Handler) http.Handler {
7248
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
7349
if r.Method == http.MethodOptions {
7450
next.ServeHTTP(w, r)
@@ -90,7 +66,7 @@ func (s *Service) Middleware(next http.Handler) http.Handler {
9066
}
9167

9268
// validate the request and get the user
93-
user, err := s.validateRequest(r)
69+
user, err := s.validateHTTPRequest(r)
9470
if err != nil {
9571
fmt.Printf("Error validating user: %v\n", err)
9672
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)

integrations/idp-go-sdk/idp/auth_token_validation.go renamed to integrations/idp-go-sdk/idp/token_validation.go

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,32 +10,34 @@ const ServiceName = "fancyanalytics-idp"
1010

1111
var SigningMethod = jwt.SigningMethodRS256
1212

13-
// validateToken validates the given JWT token string and returns the user ID if the token is valid.
14-
func (s *Service) validateToken(tokenString string) (string, error) {
13+
// ValidateToken validates the provided JWT token string and returns the associated user if the token is valid.
14+
func (s *Service) ValidateToken(token string) (*User, error) {
1515
parser := jwt.NewParser(
1616
jwt.WithValidMethods([]string{SigningMethod.Alg()}),
1717
jwt.WithIssuer(ServiceName),
1818
)
1919

20-
token, err := parser.ParseWithClaims(
21-
tokenString,
20+
t, err := parser.ParseWithClaims(
21+
token,
2222
&jwt.RegisteredClaims{},
2323
s.tokenKeyFunc,
2424
)
2525
if err != nil {
26-
return "", fmt.Errorf("failed to parse token: %w", err)
26+
return nil, fmt.Errorf("failed to parse token: %w", err)
2727
}
2828

29-
claims, ok := token.Claims.(*jwt.RegisteredClaims)
30-
if !ok || !token.Valid {
31-
return "", ErrInvalidToken
29+
claims, ok := t.Claims.(*jwt.RegisteredClaims)
30+
if !ok || !t.Valid {
31+
return nil, ErrInvalidToken
3232
}
3333

3434
if claims.Issuer != ServiceName {
35-
return "", ErrInvalidToken
35+
return nil, ErrInvalidToken
3636
}
3737

38-
return claims.Subject, nil
38+
userID := claims.Subject
39+
40+
return s.GetUser(userID)
3941
}
4042

4143
// tokenKeyFunc is a helper function that returns the public key for validating the token's signature.

0 commit comments

Comments
 (0)