Skip to content
This repository has been archived by the owner on May 19, 2020. It is now read-only.

Commit

Permalink
Merge pull request #1123 from 18F/lkb-existing_user_org_invite
Browse files Browse the repository at this point in the history
[Backend] Add the user check to see if is verified
  • Loading branch information
jcscottiii authored Jun 15, 2017
2 parents 0d0f157 + a10b544 commit 3f90002
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 14 deletions.
59 changes: 52 additions & 7 deletions controllers/uaa.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ func readBodyToStruct(rawBody io.ReadCloser, obj interface{}) (err *UaaError) {
[]byte("{\"status\": \"failure\", \"data\": \"no body in request.\"}")}
return
}
defer rawBody.Close()
body, readErr := ioutil.ReadAll(rawBody)
if readErr != nil {
err = &UaaError{http.StatusBadRequest,
[]byte("{\"status\": \"failure\", \"data\": \"" +
readErr.Error() + "\"}")}
return
}
fmt.Println(string(body))

// Read the response from inviting the user.
jsonErr := json.Unmarshal(body, obj)
Expand Down Expand Up @@ -86,6 +86,15 @@ type inviteUAAUserRequest struct {
Emails []string `json:"emails"`
}

// GetUAAUserResponse is the expected form of a response from querying UAA
// for a specific user. It is only a partial representation.
type GetUAAUserResponse struct {
Active bool `json:"active"`
Verified bool `json:"verified"`
ID string `json:"id"`
ExternalID string `json:"externalId"`
}

// InviteUAAUserResponse is the expected form of a response from invite users
// to UAA.
type InviteUAAUserResponse struct {
Expand Down Expand Up @@ -134,6 +143,7 @@ func (c *UAAContext) InviteUAAuser(
return
}
resp := w.Result()

err = readBodyToStruct(resp.Body, &inviteResponse)
return
}
Expand Down Expand Up @@ -203,6 +213,7 @@ func (c *UAAContext) InviteUserToOrg(rw web.ResponseWriter, req *web.Request) {

// Try to invite the user to UAA.
inviteResponse, err := c.InviteUAAuser(inviteUserToOrgRequest)

if err != nil {
err.writeTo(rw)
return
Expand All @@ -224,17 +235,51 @@ func (c *UAAContext) InviteUserToOrg(rw web.ResponseWriter, req *web.Request) {
return
}

// Trigger the e-mail invite.
err = c.TriggerInvite(inviteEmailRequest{
Email: userInvite.Email,
InviteURL: userInvite.InviteLink,
})
verifyResp, err := c.GetUAAUser(userInvite)
if err != nil {
err.writeTo(rw)
return
}

if verifyResp.Verified == false {
// Trigger the e-mail invite.
err = c.TriggerInvite(inviteEmailRequest{
Email: userInvite.Email,
InviteURL: userInvite.InviteLink,
})
if err != nil {
err.writeTo(rw)
return
}
}

rw.WriteHeader(http.StatusOK)
rw.Write([]byte("{\"status\": \"success\", \"userGuid\": \"" + userInvite.UserID + "\"}"))
rw.Write([]byte(fmt.Sprintf("{\"status\": \"success\", "+
"\"userGuid\": \"%s\", "+
"\"verified\": %t}", userInvite.UserID, verifyResp.Verified)))
}

// GetUAAUser will query UAA for a particular user.
func (c *UAAContext) GetUAAUser(userInvite NewInvite) (
verifyResp GetUAAUserResponse, err *UaaError) {
reqURL := fmt.Sprintf("%s%s%s", "/Users/", userInvite.UserID, "")

reqVerify, _ := http.NewRequest("GET", reqURL, nil)
w := httptest.NewRecorder()
c.uaaProxy(w, reqVerify, reqURL, true)
if w.Code != http.StatusOK {
resp := w.Result()
body, _ := ioutil.ReadAll(resp.Body)
err = &UaaError{http.StatusInternalServerError,
[]byte("{\"status\": \"failure\", \"data\": \"" +
"unable to create user in UAA database.\", \"proxy-data\": \"" +
string(body) + "\"}")}
return
}
resp := w.Result()

err = readBodyToStruct(resp.Body, &verifyResp)
return
}

type inviteEmailRequest struct {
Expand Down
57 changes: 54 additions & 3 deletions controllers/uaa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ var inviteUsersTest = []BasicProxyTest{
Response: "{\"new_invites\": [{\"email\": \"test@example.com\", \"userId\": \"user-guid\"}]}",
ResponseCode: http.StatusOK,
},
{
RequestMethod: "GET",
ExpectedPath: "/Users/user-guid",
ResponseCode: http.StatusOK,
Response: "{\"active\": true, \"verified\": false, \"id\": \"user-guid\", \"externalId\": \"user-guid@domain.com\" }",
},
{
RequestMethod: "POST",
ExpectedPath: "/v2/users",
Expand All @@ -93,7 +99,7 @@ var inviteUsersTest = []BasicProxyTest{
{
BasicSecureTest: BasicSecureTest{
BasicConsoleUnitTest: BasicConsoleUnitTest{
TestName: "UAA Invite User with e-mail in body but missing invite url",
TestName: "UAA Invite User with e-mail in body but missing e-mail",
SessionData: ValidTokenData,
EnvVars: GetMockCompleteEnvVars(),
},
Expand All @@ -107,9 +113,15 @@ var inviteUsersTest = []BasicProxyTest{
{
RequestMethod: "POST",
ExpectedPath: "/invite_users",
Response: "{\"new_invites\": [{\"email\": \"test@example.com\", \"userId\": \"user-guid\"}]}",
Response: "{\"new_invites\": [{\"inviteLink\": \"http://some.link\", \"userId\": \"user-guid\"}]}",
ResponseCode: http.StatusOK,
},
{
RequestMethod: "GET",
ExpectedPath: "/Users/user-guid",
ResponseCode: http.StatusOK,
Response: "{\"active\": true, \"verified\": false, \"id\": \"user-guid\", \"externalId\": \"user-guid@domain.com\" }",
},
{
RequestMethod: "POST",
ExpectedPath: "/v2/users",
Expand All @@ -124,7 +136,7 @@ var inviteUsersTest = []BasicProxyTest{
SessionData: ValidTokenData,
EnvVars: GetMockCompleteEnvVars(),
},
ExpectedResponse: "{\"status\": \"success\", \"userGuid\": \"user-guid\"}",
ExpectedResponse: "{\"status\": \"success\", \"userGuid\": \"user-guid\", \"verified\": false}",
ExpectedCode: http.StatusOK,
},
RequestMethod: "POST",
Expand All @@ -137,6 +149,45 @@ var inviteUsersTest = []BasicProxyTest{
Response: "{\"new_invites\": [{\"email\": \"test@example.com\", \"userId\": \"user-guid\", \"inviteLink\": \"http://some.link\"}]}",
ResponseCode: http.StatusOK,
},
{
RequestMethod: "GET",
ExpectedPath: "/Users/user-guid",
ResponseCode: http.StatusOK,
Response: "{\"active\": true, \"verified\": false, \"id\": \"user-guid\", \"externalId\": \"user-guid@domain.com\" }",
},
{
RequestMethod: "POST",
ExpectedPath: "/v2/users",
ResponseCode: http.StatusCreated,
},
},
},
{
BasicSecureTest: BasicSecureTest{
BasicConsoleUnitTest: BasicConsoleUnitTest{
TestName: "UAA Invite User with already verified user",
SessionData: ValidTokenData,
EnvVars: GetMockCompleteEnvVars(),
},
ExpectedResponse: "{\"status\": \"success\", \"userGuid\": \"user-guid\", \"verified\": true}",
ExpectedCode: http.StatusOK,
},
RequestMethod: "POST",
RequestPath: "/uaa/invite/users",
RequestBody: []byte("{\"email\": \"test@example.com\"}"),
Handlers: []Handler{
{
RequestMethod: "POST",
ExpectedPath: "/invite_users",
Response: "{\"new_invites\": [{\"email\": \"test@example.com\", \"userId\": \"user-guid\", \"inviteLink\": \"http://some.link\"}]}",
ResponseCode: http.StatusOK,
},
{
RequestMethod: "GET",
ExpectedPath: "/Users/user-guid",
ResponseCode: http.StatusOK,
Response: "{\"active\": true, \"verified\": true, \"id\": \"user-guid\", \"externalId\": \"user-guid@domain.com\" }",
},
{
RequestMethod: "POST",
ExpectedPath: "/v2/users",
Expand Down
2 changes: 1 addition & 1 deletion helpers/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ func (s *Settings) InitSettings(envVars EnvVars, env *cfenv.App) error {
s.HighPrivilegedOauthConfig = &clientcredentials.Config{
ClientID: envVars.ClientID,
ClientSecret: envVars.ClientSecret,
Scopes: []string{"scim.invite", "cloud_controller.admin"},
Scopes: []string{"scim.invite", "cloud_controller.admin", "scim.read"},
TokenURL: envVars.UAAURL + "/oauth/token",
}

Expand Down
3 changes: 3 additions & 0 deletions helpers/testhelpers/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ func CreateTestMailCatcher() (string, string, string, func()) {
}
u, _ := url.Parse(pool.Client.Endpoint())
hostname := u.Hostname()
if hostname == "" {
hostname = "localhost"
}
if err = pool.Retry(func() error {
_, dialErr := redis.Dial("tcp", hostname+":"+resource.GetPort("25/tcp"))

Expand Down
7 changes: 4 additions & 3 deletions helpers/testhelpers/testhelpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,9 @@ func CreateExternalServerForPrivileged(t *testing.T, test BasicProxyTest) *httpt
if err != nil {
t.Errorf("failed reading request body: %s.", err)
}
if string(body) != "client_id="+GetMockCompleteEnvVars().ClientID+"&grant_type=client_credentials&scope=scim.invite+cloud_controller.admin" {
t.Errorf("payload = %q; want %q", string(body), "client_id="+GetMockCompleteEnvVars().ClientID+"&grant_type=client_credentials&scope=scim.invite")
expectedRequestBody := "client_id=" + GetMockCompleteEnvVars().ClientID + "&grant_type=client_credentials&scope=scim.invite+cloud_controller.admin+scim.read"
if string(body) != expectedRequestBody {
t.Errorf("payload = %q; want %q", string(body), expectedRequestBody)
}
w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
// Write the privileged token so that it can be used.
Expand All @@ -225,7 +226,7 @@ func CreateExternalServerForPrivileged(t *testing.T, test BasicProxyTest) *httpt
}
if !foundHandler {
t.Errorf("Test name: (%s) Server received method %s\n", test.TestName, r.Method)
t.Errorf("Debug path: Got (%s) sent (%s)\n", r.URL.Path, test.RequestPath)
t.Errorf("Debug path: Got stuck on (%s) after frontend sent (%s)\n", r.URL.Path, test.RequestPath)
t.Errorf("Tried the following handlers %+v\n", test.Handlers)
}
}
Expand Down

0 comments on commit 3f90002

Please sign in to comment.