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

[Backend] Add the user check to see if is verified #1123

Merged
merged 17 commits into from
Jun 15, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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