github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/thirdparty/crowd.go (about) 1 package thirdparty 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "io/ioutil" 7 "net/http" 8 "net/url" 9 10 "github.com/mongodb/grip" 11 "github.com/pkg/errors" 12 ) 13 14 type CrowdUser struct { 15 Active bool `json:"active"` 16 DispName string `json:"display-name"` 17 EmailAddress string `json:"email"` 18 FirstName string `json:"first-name"` 19 LastName string `json:"last-name"` 20 Name string `json:"name"` 21 } 22 23 type Session struct { 24 Expand string `json:"active"` 25 CreatedDate int64 `json:"created-date"` 26 ExpiryDate int64 `json:"expiry-date"` 27 User SessionUser `json:"user"` 28 Link SessionLink `json:"link"` 29 Token string `json:"token"` 30 } 31 32 type SessionUser struct { 33 Name string `json:"name"` 34 Link SessionLink `json:"link"` 35 } 36 37 type SessionLink struct { 38 Href string `json:"href"` 39 Rel string `json:"rel"` 40 } 41 42 type WrapCrowdUser struct { 43 User CrowdUser `json:"user"` 44 } 45 46 func (self *CrowdUser) DisplayName() string { 47 return self.DispName 48 } 49 50 func (self *CrowdUser) Email() string { 51 return self.EmailAddress 52 } 53 54 func (self *CrowdUser) Username() string { 55 return self.Name 56 } 57 58 type RESTCrowdService struct { 59 crowdUsername string 60 crowdPassword string 61 apiRoot *url.URL 62 } 63 64 //NewRESTCrowdService constructs a REST-based implementation that allows 65 //fetching user info from Crowd. Takes the username/password credentials, and 66 //a URL which is the base of the REST endpoint, e.g. "https://crowd.10gen.com/" 67 68 func NewRESTCrowdService(crowdUsername string, crowdPassword string, baseUrl string) (*RESTCrowdService, error) { 69 apiRoot, err := url.Parse(baseUrl) 70 if err != nil { 71 return nil, err 72 } 73 return &RESTCrowdService{crowdUsername, crowdPassword, apiRoot}, nil 74 } 75 76 func (self *RESTCrowdService) GetUser(username string) (*CrowdUser, error) { 77 values := url.Values{} 78 values.Add("username", username) 79 subUrl, err := self.apiRoot.Parse("/crowd/rest/usermanagement/latest/user?" + values.Encode()) 80 if err != nil { 81 return nil, errors.Wrap(err, "invalid URL") 82 } 83 84 req, err := http.NewRequest("GET", subUrl.String(), nil) 85 if err != nil { 86 return nil, errors.Wrap(err, "Could not create request") 87 } 88 89 req.Header.Add("Accept", "application/json") 90 req.Header.Add("Content-Type", "application/json") 91 req.SetBasicAuth(self.crowdUsername, self.crowdPassword) 92 client := &http.Client{} 93 resp, err := client.Do(req) 94 95 if err != nil { 96 return nil, errors.Wrap(err, "Error making http request") 97 } 98 99 if resp.StatusCode != http.StatusOK { 100 return nil, errors.Errorf("Received unexpected status code from crowd: %v", resp.StatusCode) 101 } 102 result := CrowdUser{} 103 104 defer resp.Body.Close() 105 body, err := ioutil.ReadAll(resp.Body) 106 if err != nil { 107 return nil, errors.Errorf("Error occurred reading data from response: %v", resp.StatusCode) 108 } 109 110 err = json.Unmarshal(body, &result) 111 if err != nil { 112 return nil, errors.Wrap(err, "Error parsing json from crowd") 113 } 114 115 return &result, nil 116 } 117 118 func (self *RESTCrowdService) GetUserFromToken(token string) (*CrowdUser, error) { 119 // Note: at this point the token is the actual token string. 120 121 subUrl, err := self.apiRoot.Parse("/crowd/rest/usermanagement/latest/session/" + token) 122 if err != nil { 123 return nil, errors.Wrap(err, "invalid URL") 124 } 125 126 req, err := http.NewRequest("GET", subUrl.String(), nil) 127 if err != nil { 128 return nil, errors.Wrap(err, "Could not create request") 129 } 130 131 req.Header.Add("Accept", "application/json") 132 req.Header.Add("Content-Type", "application/json") 133 req.SetBasicAuth(self.crowdUsername, self.crowdPassword) 134 client := &http.Client{} 135 resp, err := client.Do(req) 136 if err != nil { 137 return nil, errors.Wrap(err, "Error making http request") 138 } 139 140 defer resp.Body.Close() 141 142 if resp.StatusCode != http.StatusOK { 143 return nil, errors.Errorf("Received unexpected status code from crowd: %v", resp.StatusCode) 144 } 145 146 body, err := ioutil.ReadAll(resp.Body) 147 if err != nil { 148 return nil, errors.Errorf("Error occurred reading data from response: %v", resp.StatusCode) 149 } 150 151 result := WrapCrowdUser{} 152 err = json.Unmarshal(body, &result) 153 if err != nil { 154 return nil, errors.Wrap(err, "Error parsing json from crowd") 155 } 156 157 return &(result.User), nil 158 } 159 160 func (self *RESTCrowdService) CreateSession(username, password string) (*Session, error) { 161 grip.Debugf("Requesting user session for '%v' from crowd", username) 162 subUrl, err := self.apiRoot.Parse("/crowd/rest/usermanagement/latest/session") 163 if err != nil { 164 return nil, errors.Wrap(err, "invalid URL") 165 } 166 postData := map[string]string{ 167 "username": username, 168 "password": password, 169 } 170 jsonBytes, err := json.Marshal(postData) 171 if err != nil { 172 return nil, errors.WithStack(err) 173 } 174 req, err := http.NewRequest("POST", subUrl.String(), ioutil.NopCloser(bytes.NewReader(jsonBytes))) 175 if err != nil { 176 return nil, errors.Wrap(err, "Could not create request") 177 } 178 req.Header.Add("Accept", "application/json") 179 req.Header.Add("Content-Type", "application/json") 180 req.SetBasicAuth(self.crowdUsername, self.crowdPassword) 181 182 client := &http.Client{} 183 resp, err := client.Do(req) 184 if err != nil { 185 return nil, errors.Wrap(err, "error making http request") 186 } 187 if resp == nil { 188 return nil, errors.Errorf("received nil response from %v", subUrl.String()) 189 } 190 defer resp.Body.Close() 191 192 if resp.StatusCode != http.StatusCreated { 193 return nil, errors.Errorf("(%v) received unexpected status code from crowd", 194 resp.StatusCode) 195 } 196 session := &Session{} 197 body, err := ioutil.ReadAll(resp.Body) 198 if err != nil { 199 return nil, errors.Wrapf(err, "(%v) error occurred reading data from response", 200 resp.StatusCode) 201 } 202 203 if err = json.Unmarshal(body, session); err != nil { 204 return nil, errors.Wrap(err, "error parsing json from crowd") 205 } 206 return session, nil 207 }