11package cf
22
33import (
4+ "encoding/base64"
5+ "encoding/json"
46 "fmt"
57 "net/url"
68 "os"
@@ -11,66 +13,105 @@ import (
1113 "golang.org/x/oauth2"
1214)
1315
16+ type Logger interface {
17+ Info (tag , message string )
18+ Error (tag , message string )
19+ }
20+
1421type AuthService struct {
1522 client * cf.Client
23+ logger Logger
1624}
1725
18- func NewAuthService (client * cf.Client ) * AuthService {
26+ func NewAuthService (client * cf.Client , logger Logger ) * AuthService {
1927 return & AuthService {
2028 client : client ,
29+ logger : logger ,
2130 }
2231}
2332
2433func (service * AuthService ) Verify (auth string ) error {
34+ tag := "AuthService.Verify"
35+ service .logger .Info (tag , "Starting verification process" )
2536 username , err := getUsername (auth )
2637 if err != nil {
38+ service .logger .Error (tag , fmt .Sprintf ("Error getting username: %v" , err ))
2739 return err
2840 }
41+ service .logger .Info (tag , fmt .Sprintf ("Username obtained: %s" , username ))
2942
3043 user , err := service .getUser (username )
3144 if err != nil {
45+ service .logger .Error (tag , fmt .Sprintf ("Error getting user: %v" , err ))
3246 return err
3347 }
48+ // Debugging = noisy
49+ // service.logger.Info(tag, fmt.Sprintf("User obtained: %v", user))
3450
3551 roles , err := service .getUserRoles (user )
3652 if err != nil {
53+ service .logger .Error (tag , fmt .Sprintf ("Error getting user roles: %v" , err ))
3754 return err
3855 }
56+ // Debugging = noisy
57+ // service.logger.Info(tag, fmt.Sprintf("User roles obtained: %v", roles))
58+
59+ tokenScopes , err := getTokenScopes (auth , service .logger )
60+ if err != nil {
61+ service .logger .Error (tag , fmt .Sprintf ("Error getting token scopes: %v" , err ))
62+ return err
63+ }
64+ service .logger .Info (tag , fmt .Sprintf ("Token scopes obtained: %v" , tokenScopes ))
3965
4066 // Check all the roles, but return good early if we find one that works.
67+
68+ // Check token scopes for cloud_controller.admin
69+ for _ , scope := range tokenScopes {
70+ if scope == "cloud_controller.admin" {
71+ service .logger .Info (tag , "User has cloud_controller.admin scope" )
72+ return nil
73+ }
74+ }
75+
76+ // Check CF roles for space_manager or space_developer
4177 for _ , role := range roles {
42- // NOTE: we should definitely be checking space IDs, too, but that's tomorrow
43- // guy's problem.
4478 if role .Type == "space_manager" || role .Type == "space_developer" {
79+ service .logger .Info (tag , fmt .Sprintf ("User has role: %s" , role .Type ))
4580 return nil
4681 }
4782 }
4883
84+ service .logger .Error (tag , "User does not have sufficient permissions" )
4985 return fmt .Errorf ("insufficient permissions" )
5086}
5187
5288func (service * AuthService ) getUser (username string ) (cf.User , error ) {
89+ tag := "AuthService.getUser"
5390 query := url.Values {}
5491 query .Add ("username" , username )
5592
5693 users , err := service .client .ListUsersByQuery (query )
5794 if err != nil {
95+ service .logger .Error (tag , fmt .Sprintf ("Error listing users by query: %v" , err ))
5896 return cf.User {}, err
5997 }
6098
6199 user := users .GetUserByUsername (username )
62100 if len (user .Guid ) == 0 {
101+ service .logger .Error (tag , "No such user found" )
63102 return cf.User {}, fmt .Errorf ("no such user" )
64103 }
65104
66105 return user , nil
67106}
68107
69108func (service * AuthService ) getUserRoles (user cf.User ) ([]cf.V3Role , error ) {
109+ tag := "AuthService.getUserRoles"
70110 roleQuery := url.Values {}
71111 roleQuery .Add ("user_guids" , user .Guid )
72112 roles , err := service .client .ListV3RolesByQuery (roleQuery )
73113 if err != nil {
114+ service .logger .Error (tag , fmt .Sprintf ("Error listing V3 roles by query: %v" , err ))
74115 return nil , err
75116 }
76117
@@ -125,3 +166,48 @@ func getBearer(auth string) (string, error) {
125166
126167 return parts [bearerLoc + 1 ], nil
127168}
169+
170+ // JWTClaims represents the claims in the JWT token
171+ type JWTClaims struct {
172+ Scope []string `json:"scope"`
173+ }
174+
175+ // DecodeJWT decodes the JWT token and extracts the claims
176+ func DecodeJWT (token string ) (* JWTClaims , error ) {
177+ parts := strings .Split (token , "." )
178+ if len (parts ) < 3 {
179+ return nil , fmt .Errorf ("invalid token format" )
180+ }
181+
182+ payload := parts [1 ]
183+ payloadDecoded , err := base64 .RawURLEncoding .DecodeString (payload )
184+ if err != nil {
185+ return nil , fmt .Errorf ("failed to decode payload: %v" , err )
186+ }
187+
188+ var claims JWTClaims
189+ err = json .Unmarshal (payloadDecoded , & claims )
190+ if err != nil {
191+ return nil , fmt .Errorf ("failed to unmarshal claims: %v" , err )
192+ }
193+
194+ return & claims , nil
195+ }
196+
197+ func getTokenScopes (auth string , logger Logger ) ([]string , error ) {
198+ tag := "AuthService.getTokenScopes"
199+ bearer , err := getBearer (auth )
200+ if err != nil {
201+ logger .Error (tag , fmt .Sprintf ("Error getting bearer token: %v" , err ))
202+ return nil , err
203+ }
204+
205+ claims , err := DecodeJWT (bearer )
206+ if err != nil {
207+ logger .Error (tag , fmt .Sprintf ("Error decoding JWT token: %v" , err ))
208+ return nil , err
209+ }
210+
211+ logger .Info (tag , fmt .Sprintf ("Scopes found in token: %v" , claims .Scope ))
212+ return claims .Scope , nil
213+ }
0 commit comments