github.com/circl-dev/go-swagger@v0.31.0/examples/composed-auth/auth/authorizers.go (about) 1 package auth 2 3 import ( 4 "crypto/rsa" 5 "io/ioutil" 6 7 models "github.com/circl-dev/go-swagger/examples/composed-auth/models" 8 jwt "github.com/dgrijalva/jwt-go" 9 errors "github.com/go-openapi/errors" 10 ) 11 12 const ( 13 // currently unused: privateKeyPath = "keys/apiKey.prv" 14 publicKeyPath = "keys/apiKey.pem" 15 issuerName = "example.com" 16 ) 17 18 var ( 19 userDb map[string]string 20 21 // Keys used to sign and verify our tokens 22 verifyKey *rsa.PublicKey 23 // currently unused: signKey *rsa.PrivateKey 24 ) 25 26 // roleClaims describes the format of our JWT token's claims 27 type roleClaims struct { 28 Roles []string `json:"roles"` 29 jwt.StandardClaims 30 } 31 32 func init() { 33 // emulates the loading of a local users database 34 userDb = map[string]string{ 35 "fred": "scrum", 36 "ivan": "terrible", 37 } 38 39 // loads public keys to verify our tokens 40 verifyKeyBuf, err := ioutil.ReadFile(publicKeyPath) 41 if err != nil { 42 panic("Cannot load public key for tokens") 43 } 44 verifyKey, err = jwt.ParseRSAPublicKeyFromPEM(verifyKeyBuf) 45 if err != nil { 46 panic("Invalid public key for tokens") 47 } 48 } 49 50 // Customized authorizer methods for our sample API 51 52 // IsRegistered determines if the user is properly registered, 53 // i.e if a valid username:password pair has been provided 54 func IsRegistered(user, pass string) (*models.Principal, error) { 55 if password, ok := userDb[user]; ok { 56 if pass == password { 57 return &models.Principal{ 58 Name: user, 59 }, nil 60 } 61 } 62 return nil, errors.New(401, "Unauthorized: not a registered user") 63 } 64 65 // IsReseller tells if the API key is a JWT signed by us with a claim to be a reseller 66 func IsReseller(token string) (*models.Principal, error) { 67 claims, err := parseAndCheckToken(token) 68 if err == nil { 69 if claims.Issuer == issuerName && claims.Id != "" { 70 isReseller := false 71 for _, role := range claims.Roles { 72 if role == "reseller" { 73 isReseller = true 74 break 75 } 76 } 77 if isReseller { 78 return &models.Principal{ 79 Name: claims.Id, 80 }, nil 81 } 82 return nil, errors.New(403, "Forbidden: insufficient API key privileges") 83 } 84 } 85 return nil, errors.New(401, "Unauthorized: invalid API key token: %v", err) 86 } 87 88 // HasRole tells if the Bearer token is a JWT signed by us with a claim to be 89 // member of an authorization scope. 90 // We verify that the claimed role is one of the passed scopes 91 func HasRole(token string, scopes []string) (*models.Principal, error) { 92 claims, err := parseAndCheckToken(token) 93 if err == nil { 94 if claims.Issuer == issuerName { 95 isInScopes := false 96 claimedRoles := []string{} 97 for _, scope := range scopes { 98 for _, role := range claims.Roles { 99 if role == scope { 100 isInScopes = true 101 // we enrich the principal with all claimed roles within scope (hence: not breaking here) 102 claimedRoles = append(claimedRoles, role) 103 } 104 } 105 } 106 if isInScopes { 107 return &models.Principal{ 108 Name: claims.Id, 109 Roles: claimedRoles, 110 }, nil 111 } 112 return nil, errors.New(403, "Forbidden: insufficient privileges") 113 } 114 } 115 return nil, errors.New(401, "Unauthorized: invalid Bearer token: %v", err) 116 } 117 118 func parseAndCheckToken(token string) (*roleClaims, error) { 119 // the API key is a JWT signed by us with a claim to be a reseller 120 parsedToken, err := jwt.ParseWithClaims(token, &roleClaims{}, func(parsedToken *jwt.Token) (interface{}, error) { 121 // the key used to validate tokens 122 return verifyKey, nil 123 }) 124 125 if err == nil { 126 if claims, ok := parsedToken.Claims.(*roleClaims); ok && parsedToken.Valid { 127 return claims, nil 128 } 129 } 130 return nil, err 131 132 }