bitbucket.go (3809B)
1 package oauth2 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io/ioutil" 7 "net/http" 8 "strings" 9 10 "github.com/tarent/loginsrv/model" 11 ) 12 13 var bitbucketAPI = "https://api.bitbucket.org/2.0" 14 15 // Using the avatar url to be able to fetch 128px image. By default BitbucketAPI return 32px image. 16 var bitbucketAvatarURL = "https://bitbucket.org/account/%v/avatar/128/" 17 18 func init() { 19 RegisterProvider(providerBitbucket) 20 } 21 22 // bitbucketUser is used for parsing the github response 23 type bitbucketUser struct { 24 Username string `json:"username,omitempty"` 25 DisplayName string `json:"display_name,omitempty"` 26 Email string `json:"email,omitempty"` 27 } 28 29 // emails is used to parse user email information 30 type emails struct { 31 Page int `json:"page,omitempty"` 32 PageLen int `json:"pagelen,omitempty"` 33 Size int `json:"size,omitempty"` 34 Values []email 35 } 36 37 // email used to parse one user's email 38 type email struct { 39 Email string `json:"email,omitempty"` 40 IsConfirmed bool `json:"is_confirmed,omitempty"` 41 IsPrimary bool `json:"is_primary,omitempty"` 42 Links struct { 43 Self struct { 44 Href string 45 } 46 } `json:"links,omitempty"` 47 Type string `json:"type,omitempty"` 48 } 49 50 // getPrimaryEmailAddress retrieve the primary email address of the user 51 func (e *emails) getPrimaryEmailAddress() string { 52 for _, val := range e.Values { 53 if val.IsPrimary { 54 return val.Email 55 } 56 } 57 return "" 58 } 59 60 // getBitbucketEmails Retrieves bitbucket user emails from the Bitbucket API emails service 61 func getBitbucketEmails(token TokenInfo) (emails, error) { 62 emailUrl := fmt.Sprintf("%v/user/emails?access_token=%v", bitbucketAPI, token.AccessToken) 63 userEmails := emails{} 64 resp, err := http.Get(emailUrl) 65 66 if err != nil { 67 return emails{}, err 68 } 69 defer resp.Body.Close() 70 71 if !strings.Contains(resp.Header.Get("Content-Type"), "application/json") { 72 return emails{}, fmt.Errorf("wrong content-type on bitbucket get user emails: %v", resp.Header.Get("Content-Type")) 73 } 74 75 if resp.StatusCode != 200 { 76 return emails{}, fmt.Errorf("got http status %v on bitbucket get user emails", resp.StatusCode) 77 } 78 79 b, err := ioutil.ReadAll(resp.Body) 80 if err != nil { 81 return emails{}, fmt.Errorf("error reading bitbucket get user emails: %v", err) 82 } 83 84 err = json.Unmarshal(b, &userEmails) 85 86 if err != nil { 87 return emails{}, fmt.Errorf("error parsing bitbucket get user emails: %v", err) 88 } 89 90 return userEmails, nil 91 } 92 93 var providerBitbucket = Provider{ 94 Name: "bitbucket", 95 AuthURL: "https://bitbucket.org/site/oauth2/authorize", 96 TokenURL: "https://bitbucket.org/site/oauth2/access_token", 97 GetUserInfo: func(token TokenInfo) (model.UserInfo, string, error) { 98 gu := bitbucketUser{} 99 url := fmt.Sprintf("%v/user?access_token=%v", bitbucketAPI, token.AccessToken) 100 resp, err := http.Get(url) 101 if err != nil { 102 return model.UserInfo{}, "", err 103 } 104 defer resp.Body.Close() 105 106 if !strings.Contains(resp.Header.Get("Content-Type"), "application/json") { 107 return model.UserInfo{}, "", fmt.Errorf("wrong content-type on bitbucket get user info: %v", resp.Header.Get("Content-Type")) 108 } 109 110 if resp.StatusCode != 200 { 111 return model.UserInfo{}, "", fmt.Errorf("got http status %v on bitbucket get user info", resp.StatusCode) 112 } 113 114 b, err := ioutil.ReadAll(resp.Body) 115 if err != nil { 116 return model.UserInfo{}, "", fmt.Errorf("error reading bitbucket get user info: %v", err) 117 } 118 119 err = json.Unmarshal(b, &gu) 120 121 if err != nil { 122 return model.UserInfo{}, "", fmt.Errorf("error parsing bitbucket get user info: %v", err) 123 } 124 125 userEmails, err := getBitbucketEmails(token) 126 127 return model.UserInfo{ 128 Sub: gu.Username, 129 Picture: fmt.Sprintf(bitbucketAvatarURL, gu.Username), 130 Name: gu.DisplayName, 131 Email: userEmails.getPrimaryEmailAddress(), 132 Origin: "bitbucket", 133 }, string(b), nil 134 }, 135 }