github.com/IBM-Cloud/bluemix-go@v0.0.0-20240423071914-9e96525baef4/authentication/iam.go (about) 1 package authentication 2 3 import ( 4 "encoding/base64" 5 "fmt" 6 7 bluemix "github.com/IBM-Cloud/bluemix-go" 8 "github.com/IBM-Cloud/bluemix-go/bmxerror" 9 "github.com/IBM-Cloud/bluemix-go/rest" 10 ) 11 12 //IAMError ... 13 type IAMError struct { 14 ErrorCode string `json:"errorCode"` 15 ErrorMessage string `json:"errorMessage"` 16 ErrorDetails string `json:"errorDetails"` 17 } 18 19 //Description ... 20 func (e IAMError) Description() string { 21 if e.ErrorDetails != "" { 22 return e.ErrorDetails 23 } 24 return e.ErrorMessage 25 } 26 27 //IAMTokenResponse ... 28 type IAMTokenResponse struct { 29 AccessToken string `json:"access_token"` 30 RefreshToken string `json:"refresh_token"` 31 UAAAccessToken string `json:"uaa_token"` 32 UAARefreshToken string `json:"uaa_refresh_token"` 33 TokenType string `json:"token_type"` 34 } 35 36 //IAMAuthRepository ... 37 type IAMAuthRepository struct { 38 config *bluemix.Config 39 client *rest.Client 40 endpoint string 41 } 42 43 //NewIAMAuthRepository ... 44 func NewIAMAuthRepository(config *bluemix.Config, client *rest.Client) (*IAMAuthRepository, error) { 45 var endpoint string 46 47 if config.TokenProviderEndpoint != nil { 48 endpoint = *config.TokenProviderEndpoint 49 } else { 50 var err error 51 endpoint, err = config.EndpointLocator.IAMEndpoint() 52 if err != nil { 53 return nil, err 54 } 55 } 56 57 return &IAMAuthRepository{ 58 config: config, 59 client: client, 60 endpoint: endpoint, 61 }, nil 62 } 63 64 //AuthenticatePassword ... 65 func (auth *IAMAuthRepository) AuthenticatePassword(username string, password string) error { 66 return auth.getToken(map[string]string{ 67 "grant_type": "password", 68 "username": username, 69 "password": password, 70 }) 71 } 72 73 //AuthenticateAPIKey ... 74 func (auth *IAMAuthRepository) AuthenticateAPIKey(apiKey string) error { 75 return auth.getToken(map[string]string{ 76 "grant_type": "urn:ibm:params:oauth:grant-type:apikey", 77 "apikey": apiKey, 78 }) 79 } 80 81 //AuthenticateSSO ... 82 func (auth *IAMAuthRepository) AuthenticateSSO(passcode string) error { 83 return auth.getToken(map[string]string{ 84 "grant_type": "urn:ibm:params:oauth:grant-type:passcode", 85 "passcode": passcode, 86 }) 87 } 88 89 //RefreshToken ... 90 func (auth *IAMAuthRepository) RefreshToken() (string, error) { 91 data := map[string]string{ 92 "grant_type": "refresh_token", 93 "refresh_token": auth.config.IAMRefreshToken, 94 } 95 96 err := auth.getToken(data) 97 if err != nil { 98 return "", err 99 } 100 101 return auth.config.IAMAccessToken, nil 102 } 103 104 //GetPasscode ... 105 func (auth *IAMAuthRepository) GetPasscode() (string, error) { 106 request := rest.PostRequest(auth.endpoint+"/identity/passcode"). 107 Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("bx:bx"))). 108 Field("grant_type", "refresh_token"). 109 Field("refresh_token", auth.config.IAMRefreshToken). 110 Field("response_type", "cloud_iam") 111 112 res := make(map[string]string, 0) 113 var apiErr IAMError 114 115 resp, err := auth.client.Do(request, &res, &apiErr) 116 if err != nil { 117 return "", err 118 } 119 120 if apiErr.ErrorCode != "" { 121 if apiErr.ErrorCode == "BXNIM0407E" { 122 return "", bmxerror.New(ErrCodeInvalidToken, apiErr.Description()) 123 } 124 return "", bmxerror.NewRequestFailure(apiErr.ErrorCode, apiErr.Description(), resp.StatusCode) 125 } 126 127 return res["passcode"], nil 128 } 129 130 func (auth *IAMAuthRepository) getToken(data map[string]string) error { 131 request := rest.PostRequest(auth.endpoint+"/identity/token"). 132 Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("bx:bx"))). 133 Field("response_type", "cloud_iam") 134 135 for k, v := range data { 136 request.Field(k, v) 137 } 138 139 var tokens IAMTokenResponse 140 var apiErr IAMError 141 142 resp, err := auth.client.Do(request, &tokens, &apiErr) 143 if err != nil { 144 return err 145 } 146 147 if apiErr.ErrorCode != "" { 148 if apiErr.ErrorCode == "BXNIM0407E" { 149 if resp != nil && resp.Header != nil { 150 return bmxerror.New(ErrCodeInvalidToken, fmt.Sprintf("Transaction-Id:%s %s", resp.Header["Transaction-Id"], apiErr.Description())) 151 } 152 return bmxerror.New(ErrCodeInvalidToken, apiErr.Description()) 153 } 154 if resp != nil && resp.Header != nil { 155 return bmxerror.NewRequestFailure(apiErr.ErrorCode, fmt.Sprintf("Transaction-Id:%s %s", resp.Header["Transaction-Id"], apiErr.Description()), resp.StatusCode) 156 } 157 return bmxerror.NewRequestFailure(apiErr.ErrorCode, apiErr.Description(), resp.StatusCode) 158 } 159 160 auth.config.IAMAccessToken = fmt.Sprintf("%s %s", tokens.TokenType, tokens.AccessToken) 161 auth.config.IAMRefreshToken = tokens.RefreshToken 162 163 return nil 164 }