github.com/asifdxtreme/cli@v6.1.3-0.20150123051144-9ead8700b4ae+incompatible/cf/api/authentication/authentication.go (about) 1 package authentication 2 3 import ( 4 "encoding/base64" 5 "fmt" 6 "net/url" 7 "strings" 8 9 . "github.com/cloudfoundry/cli/cf/i18n" 10 11 "github.com/cloudfoundry/cli/cf/configuration/core_config" 12 "github.com/cloudfoundry/cli/cf/errors" 13 "github.com/cloudfoundry/cli/cf/net" 14 ) 15 16 type TokenRefresher interface { 17 RefreshAuthToken() (updatedToken string, apiErr error) 18 } 19 20 type AuthenticationRepository interface { 21 RefreshAuthToken() (updatedToken string, apiErr error) 22 Authenticate(credentials map[string]string) (apiErr error) 23 GetLoginPromptsAndSaveUAAServerURL() (map[string]core_config.AuthPrompt, error) 24 } 25 26 type UAAAuthenticationRepository struct { 27 config core_config.ReadWriter 28 gateway net.Gateway 29 } 30 31 func NewUAAAuthenticationRepository(gateway net.Gateway, config core_config.ReadWriter) (uaa UAAAuthenticationRepository) { 32 uaa.gateway = gateway 33 uaa.config = config 34 return 35 } 36 37 func (uaa UAAAuthenticationRepository) Authenticate(credentials map[string]string) (apiErr error) { 38 data := url.Values{ 39 "grant_type": {"password"}, 40 "scope": {""}, 41 } 42 for key, val := range credentials { 43 data[key] = []string{val} 44 } 45 46 apiErr = uaa.getAuthToken(data) 47 switch response := apiErr.(type) { 48 case errors.HttpError: 49 if response.StatusCode() == 401 { 50 apiErr = errors.New(T("Credentials were rejected, please try again.")) 51 } 52 } 53 54 return 55 } 56 57 type LoginResource struct { 58 Prompts map[string][]string 59 Links map[string]string 60 } 61 62 var knownAuthPromptTypes = map[string]core_config.AuthPromptType{ 63 "text": core_config.AuthPromptTypeText, 64 "password": core_config.AuthPromptTypePassword, 65 } 66 67 func (r *LoginResource) parsePrompts() (prompts map[string]core_config.AuthPrompt) { 68 prompts = make(map[string]core_config.AuthPrompt) 69 for key, val := range r.Prompts { 70 prompts[key] = core_config.AuthPrompt{ 71 Type: knownAuthPromptTypes[val[0]], 72 DisplayName: val[1], 73 } 74 } 75 return 76 } 77 78 func (uaa UAAAuthenticationRepository) GetLoginPromptsAndSaveUAAServerURL() (prompts map[string]core_config.AuthPrompt, apiErr error) { 79 url := fmt.Sprintf("%s/login", uaa.config.AuthenticationEndpoint()) 80 resource := &LoginResource{} 81 apiErr = uaa.gateway.GetResource(url, resource) 82 83 prompts = resource.parsePrompts() 84 if resource.Links["uaa"] == "" { 85 uaa.config.SetUaaEndpoint(uaa.config.AuthenticationEndpoint()) 86 } else { 87 uaa.config.SetUaaEndpoint(resource.Links["uaa"]) 88 } 89 return 90 } 91 92 func (uaa UAAAuthenticationRepository) RefreshAuthToken() (string, error) { 93 data := url.Values{ 94 "refresh_token": {uaa.config.RefreshToken()}, 95 "grant_type": {"refresh_token"}, 96 "scope": {""}, 97 } 98 99 apiErr := uaa.getAuthToken(data) 100 updatedToken := uaa.config.AccessToken() 101 102 return updatedToken, apiErr 103 } 104 105 func (uaa UAAAuthenticationRepository) getAuthToken(data url.Values) error { 106 type uaaErrorResponse struct { 107 Code string `json:"error"` 108 Description string `json:"error_description"` 109 } 110 111 type AuthenticationResponse struct { 112 AccessToken string `json:"access_token"` 113 TokenType string `json:"token_type"` 114 RefreshToken string `json:"refresh_token"` 115 Error uaaErrorResponse `json:"error"` 116 } 117 118 path := fmt.Sprintf("%s/oauth/token", uaa.config.AuthenticationEndpoint()) 119 request, err := uaa.gateway.NewRequest("POST", path, "Basic "+base64.StdEncoding.EncodeToString([]byte("cf:")), strings.NewReader(data.Encode())) 120 if err != nil { 121 return errors.NewWithError(T("Failed to start oauth request"), err) 122 } 123 request.HttpReq.Header.Set("Content-Type", "application/x-www-form-urlencoded") 124 125 response := new(AuthenticationResponse) 126 _, err = uaa.gateway.PerformRequestForJSONResponse(request, &response) 127 128 switch err.(type) { 129 case nil: 130 case errors.HttpError: 131 return err 132 case *errors.InvalidTokenError: 133 return errors.New(T("Authentication has expired. Please log back in to re-authenticate.\n\nTIP: Use `cf login -a <endpoint> -u <user> -o <org> -s <space>` to log back in and re-authenticate.")) 134 default: 135 return errors.NewWithError(T("auth request failed"), err) 136 } 137 138 // TODO: get the actual status code 139 if response.Error.Code != "" { 140 return errors.NewHttpError(0, response.Error.Code, response.Error.Description) 141 } 142 143 uaa.config.SetAccessToken(fmt.Sprintf("%s %s", response.TokenType, response.AccessToken)) 144 uaa.config.SetRefreshToken(response.RefreshToken) 145 146 return nil 147 }