github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/cli/cmd/auth/authorize/token_provider.go (about) 1 /* 2 Copyright (C) 2022-2023 ApeCloud Co., Ltd 3 4 This file is part of KubeBlocks project 5 6 This program is free software: you can redistribute it and/or modify 7 it under the terms of the GNU Affero General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU Affero General Public License for more details. 15 16 You should have received a copy of the GNU Affero General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 package authorize 21 22 import ( 23 "context" 24 "fmt" 25 "time" 26 27 "github.com/golang-jwt/jwt" 28 "github.com/pkg/errors" 29 30 "github.com/1aal/kubeblocks/pkg/cli/cmd/auth/authorize/authenticator" 31 ) 32 33 type TokenProvider struct { 34 cached CachedTokenProvider 35 issued IssuedTokenProvider 36 } 37 38 // NewTokenProvider default constructor. 39 func NewTokenProvider(o Options) (Provider, error) { 40 cached := NewKeyringCachedTokenProvider(nil) 41 issued, err := newDefaultIssuedTokenProvider(o) 42 if err != nil { 43 return nil, errors.Wrap(err, "could not create cloud issued token provider") 44 } 45 return &TokenProvider{ 46 cached: cached, 47 issued: issued, 48 }, nil 49 } 50 51 // Abstract constructor 52 func newTokenProvider(cached CachedTokenProvider, issued IssuedTokenProvider) Provider { 53 return &TokenProvider{ 54 cached: cached, 55 issued: issued, 56 } 57 } 58 59 func (p *TokenProvider) Login(ctx context.Context) (*authenticator.UserInfoResponse, string, error) { 60 tokenResult, err := p.issued.authenticate(ctx) 61 if err != nil { 62 return nil, "", errors.Wrap(err, "could not authenticate with cloud") 63 } 64 userInfo, err := p.issued.getUserInfo(tokenResult.IDToken) 65 if err != nil { 66 return nil, "", errors.Wrap(err, "could not get user info from cloud") 67 } 68 err = p.cached.cacheUserInfo(userInfo) 69 if err != nil { 70 return nil, "", errors.Wrap(err, "could not store user info") 71 } 72 73 err = p.cached.cacheTokens(tokenResult) 74 if err != nil { 75 return nil, "", errors.Wrap(err, "could not cache tokens") 76 } 77 78 return userInfo, tokenResult.IDToken, nil 79 } 80 81 func (p *TokenProvider) Logout(ctx context.Context) error { 82 tokenResult, err := p.cached.GetTokens() 83 if err != nil { 84 return err 85 } 86 if tokenResult == nil { 87 return fmt.Errorf("token not found in cache, already logged out") 88 } 89 90 err = p.cached.deleteTokens() 91 if err != nil { 92 return err 93 } 94 95 err = p.issued.logout(ctx, tokenResult.IDToken) 96 if err != nil { 97 return err 98 } 99 return nil 100 } 101 102 func (p *TokenProvider) getTokenFromCache(isTokenValid func(authenticator.TokenResponse) bool) (*authenticator.TokenResponse, error) { 103 tokenResult, err := p.cached.GetTokens() 104 if err != nil { 105 return nil, errors.Wrap(err, "could get tokens from the cache") 106 } 107 // if the token is not in the cache, return nil 108 if tokenResult == nil { 109 return nil, nil 110 } 111 112 if isTokenValid(*tokenResult) { 113 return tokenResult, nil 114 } 115 116 if tokenResult.RefreshToken == "" { 117 return nil, nil 118 } 119 120 return p.getRefreshToken(tokenResult.RefreshToken), nil 121 } 122 123 // getRefreshToken gets a new token from the refresh token 124 func (p *TokenProvider) getRefreshToken(refreshToken string) *authenticator.TokenResponse { 125 tokenResult, err := p.issued.refreshToken(refreshToken) 126 if err != nil { 127 return nil 128 } 129 return tokenResult 130 } 131 132 // IsValidToken checks to see if the token is valid and has not expired 133 func IsValidToken(tokenString string) bool { 134 jwtParser := jwt.Parser{} 135 claims := jwt.MapClaims{} 136 if _, _, err := jwtParser.ParseUnverified(tokenString, claims); err != nil { 137 fmt.Println("Token parsing failed:", err) 138 return false 139 } 140 return claims.VerifyExpiresAt(time.Now().Unix(), true) 141 }