1package cf 2 3import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "net/http" 8 "net/http/httptest" 9 "reflect" 10 "strings" 11 "testing" 12 13 "github.com/concourse/dex/connector" 14 "github.com/sirupsen/logrus" 15) 16 17func TestOpen(t *testing.T) { 18 testServer := testSetup() 19 defer testServer.Close() 20 21 conn := newConnector(t, testServer.URL) 22 23 expectEqual(t, conn.clientID, "test-client") 24 expectEqual(t, conn.clientSecret, "secret") 25 expectEqual(t, conn.redirectURI, testServer.URL+"/callback") 26} 27 28func TestHandleCallback(t *testing.T) { 29 30 testServer := testSetup() 31 defer testServer.Close() 32 33 cfConn := &cfConnector{ 34 tokenURL: fmt.Sprintf("%s/token", testServer.URL), 35 authorizationURL: fmt.Sprintf("%s/authorize", testServer.URL), 36 userInfoURL: fmt.Sprintf("%s/userinfo", testServer.URL), 37 apiURL: testServer.URL, 38 clientSecret: "secret", 39 clientID: "test-client", 40 redirectURI: "localhost:8080/sky/dex/callback", 41 httpClient: http.DefaultClient, 42 } 43 44 req, err := http.NewRequest("GET", testServer.URL, nil) 45 expectEqual(t, err, nil) 46 47 t.Run("CallbackWithGroupsScope", func(t *testing.T) { 48 identity, err := cfConn.HandleCallback(connector.Scopes{Groups: true}, req) 49 expectEqual(t, err, nil) 50 51 expectEqual(t, len(identity.Groups), 24) 52 expectEqual(t, identity.Groups[0], "some-org-guid-1") 53 expectEqual(t, identity.Groups[1], "some-org-guid-2") 54 expectEqual(t, identity.Groups[2], "some-org-guid-3") 55 expectEqual(t, identity.Groups[3], "some-org-guid-4") 56 expectEqual(t, identity.Groups[4], "some-org-name-1") 57 expectEqual(t, identity.Groups[5], "some-org-name-1:some-space-name-1") 58 expectEqual(t, identity.Groups[6], "some-org-name-1:some-space-name-1:auditor") 59 expectEqual(t, identity.Groups[7], "some-org-name-1:some-space-name-1:developer") 60 expectEqual(t, identity.Groups[8], "some-org-name-1:some-space-name-1:manager") 61 expectEqual(t, identity.Groups[9], "some-org-name-2") 62 expectEqual(t, identity.Groups[10], "some-org-name-2:some-space-name-2") 63 expectEqual(t, identity.Groups[11], "some-org-name-2:some-space-name-2:auditor") 64 expectEqual(t, identity.Groups[12], "some-org-name-2:some-space-name-2:developer") 65 expectEqual(t, identity.Groups[13], "some-org-name-2:some-space-name-2:manager") 66 expectEqual(t, identity.Groups[14], "some-org-name-3") 67 expectEqual(t, identity.Groups[15], "some-org-name-4") 68 expectEqual(t, identity.Groups[16], "some-space-guid-1") 69 expectEqual(t, identity.Groups[17], "some-space-guid-1:auditor") 70 expectEqual(t, identity.Groups[18], "some-space-guid-1:developer") 71 expectEqual(t, identity.Groups[19], "some-space-guid-1:manager") 72 expectEqual(t, identity.Groups[20], "some-space-guid-2") 73 expectEqual(t, identity.Groups[21], "some-space-guid-2:auditor") 74 expectEqual(t, identity.Groups[22], "some-space-guid-2:developer") 75 expectEqual(t, identity.Groups[23], "some-space-guid-2:manager") 76 }) 77 78 t.Run("CallbackWithoutGroupsScope", func(t *testing.T) { 79 identity, err := cfConn.HandleCallback(connector.Scopes{}, req) 80 81 expectEqual(t, err, nil) 82 expectEqual(t, identity.UserID, "12345") 83 expectEqual(t, identity.Username, "test-user") 84 }) 85 86 t.Run("CallbackWithOfflineAccessScope", func(t *testing.T) { 87 identity, err := cfConn.HandleCallback(connector.Scopes{OfflineAccess: true}, req) 88 89 expectEqual(t, err, nil) 90 expectNotEqual(t, len(identity.ConnectorData), 0) 91 92 cData := connectorData{} 93 err = json.Unmarshal(identity.ConnectorData, &cData) 94 95 expectEqual(t, err, nil) 96 expectNotEqual(t, cData.AccessToken, "") 97 }) 98} 99 100func testSpaceHandler(reqUrl, spaceApiEndpoint string) (result map[string]interface{}) { 101 fullUrl := fmt.Sprintf("%s?order-direction=asc&page=2&results-per-page=50", spaceApiEndpoint) 102 if strings.Contains(reqUrl, fullUrl) { 103 result = map[string]interface{}{ 104 "resources": []map[string]interface{}{ 105 { 106 "metadata": map[string]string{"guid": "some-space-guid-2"}, 107 "entity": map[string]string{"name": "some-space-name-2", "organization_guid": "some-org-guid-2"}, 108 }, 109 }, 110 } 111 } else { 112 nextUrl := fmt.Sprintf("/v2/users/12345/%s?order-direction=asc&page=2&results-per-page=50", spaceApiEndpoint) 113 result = map[string]interface{}{ 114 "next_url": nextUrl, 115 "resources": []map[string]interface{}{ 116 { 117 "metadata": map[string]string{"guid": "some-space-guid-1"}, 118 "entity": map[string]string{"name": "some-space-name-1", "organization_guid": "some-org-guid-1"}, 119 }, 120 }, 121 } 122 } 123 return result 124} 125 126func testOrgHandler(reqUrl string) (result map[string]interface{}) { 127 if strings.Contains(reqUrl, "organizations?order-direction=asc&page=2&results-per-page=50") { 128 result = map[string]interface{}{ 129 "resources": []map[string]interface{}{ 130 { 131 "metadata": map[string]string{"guid": "some-org-guid-3"}, 132 "entity": map[string]string{"name": "some-org-name-3"}, 133 }, 134 { 135 "metadata": map[string]string{"guid": "some-org-guid-4"}, 136 "entity": map[string]string{"name": "some-org-name-4"}, 137 }, 138 }, 139 } 140 } else { 141 result = map[string]interface{}{ 142 "next_url": "/v2/users/12345/organizations?order-direction=asc&page=2&results-per-page=50", 143 "resources": []map[string]interface{}{ 144 { 145 "metadata": map[string]string{"guid": "some-org-guid-1"}, 146 "entity": map[string]string{"name": "some-org-name-1"}, 147 }, 148 { 149 "metadata": map[string]string{"guid": "some-org-guid-2"}, 150 "entity": map[string]string{"name": "some-org-name-2"}, 151 }, 152 }, 153 } 154 } 155 return result 156} 157 158func testSetup() *httptest.Server { 159 mux := http.NewServeMux() 160 mux.HandleFunc("/token", func(w http.ResponseWriter, r *http.Request) { 161 token := "eyJhbGciOiJSUzI1NiIsImtpZCI6ImtleS0xIiwidHlwIjoiSldUIn0.eyJqdGkiOiIxMjk4MTNhZjJiNGM0ZDNhYmYyNjljMzM4OTFkZjNiZCIsInN1YiI6ImNmMWFlODk4LWQ1ODctNDBhYS1hNWRiLTE5ZTY3MjI0N2I1NyIsInNjb3BlIjpbImNsb3VkX2NvbnRyb2xsZXIucmVhZCIsIm9wZW5pZCJdLCJjbGllbnRfaWQiOiJjb25jb3Vyc2UiLCJjaWQiOiJjb25jb3Vyc2UiLCJhenAiOiJjb25jb3Vyc2UiLCJncmFudF90eXBlIjoiYXV0aG9yaXphdGlvbl9jb2RlIiwidXNlcl9pZCI6ImNmMWFlODk4LWQ1ODctNDBhYS1hNWRiLTE5ZTY3MjI0N2I1NyIsIm9yaWdpbiI6InVhYSIsInVzZXJfbmFtZSI6ImFkbWluIiwiZW1haWwiOiJhZG1pbiIsImF1dGhfdGltZSI6MTUyMzM3NDIwNCwicmV2X3NpZyI6IjYxNWJjMTk0IiwiaWF0IjoxNTIzMzc3MTUyLCJleHAiOjE1MjM0MjAzNTIsImlzcyI6Imh0dHBzOi8vdWFhLnN0eXgucHVzaC5nY3AuY2YtYXBwLmNvbS9vYXV0aC90b2tlbiIsInppZCI6InVhYSIsImF1ZCI6WyJjbG91ZF9jb250cm9sbGVyIiwiY29uY291cnNlIiwib3BlbmlkIl19.FslbnwvW0WScVRNK8IWghRX0buXfl6qaI1K7z_dzjPUVrdEyMtaYa3kJI8srA-2G1PjSSEWa_3Vzs_BEnTc3iG0JQWU0XlcjdCdAFTvnmKiHSzffy1O_oGYyH47KXtnZOxHf3rdV_Xgw4XTqPrfKXQxnPemUAJyKf2tjgs3XToGaqqBw-D_2BQVY79kF0_GgksQsViqq1GW0Dur6m2CgBhtc2h1AQGO16izXl3uNbpW6ClhaW43NQXlE4wqtr7kfmxyOigHJb2MSQ3wwPc6pqYdUT6ka_TMqavqbxEJ4QcS6SoEcVsDTmEQ4c8dmWUgXM0AZjd0CaEGTB6FDHxH5sw" 162 w.Header().Add("Content-Type", "application/json") 163 json.NewEncoder(w).Encode(map[string]string{ 164 "access_token": token, 165 }) 166 }) 167 168 mux.HandleFunc("/v2/info", func(w http.ResponseWriter, r *http.Request) { 169 url := fmt.Sprintf("http://%s", r.Host) 170 171 json.NewEncoder(w).Encode(map[string]string{ 172 "authorization_endpoint": url, 173 }) 174 }) 175 176 mux.HandleFunc("/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { 177 url := fmt.Sprintf("http://%s", r.Host) 178 179 json.NewEncoder(w).Encode(map[string]string{ 180 "token_endpoint": url, 181 "authorization_endpoint": url, 182 "userinfo_endpoint": url, 183 }) 184 }) 185 186 mux.HandleFunc("/callback", func(w http.ResponseWriter, r *http.Request) { 187 }) 188 189 mux.HandleFunc("/userinfo", func(w http.ResponseWriter, r *http.Request) { 190 json.NewEncoder(w).Encode(map[string]string{ 191 "user_id": "12345", 192 "user_name": "test-user", 193 "email": "blah-email", 194 }) 195 }) 196 197 mux.HandleFunc("/v2/users/", func(w http.ResponseWriter, r *http.Request) { 198 var result map[string]interface{} 199 200 reqUrl := r.URL.String() 201 if strings.Contains(reqUrl, "/spaces") { 202 result = testSpaceHandler(reqUrl, "spaces") 203 } 204 205 if strings.Contains(reqUrl, "/audited_spaces") { 206 result = testSpaceHandler(reqUrl, "audited_spaces") 207 } 208 209 if strings.Contains(reqUrl, "/managed_spaces") { 210 result = testSpaceHandler(reqUrl, "managed_spaces") 211 } 212 213 if strings.Contains(reqUrl, "organizations") { 214 result = testOrgHandler(reqUrl) 215 } 216 217 json.NewEncoder(w).Encode(result) 218 }) 219 220 return httptest.NewServer(mux) 221} 222 223func newConnector(t *testing.T, serverURL string) *cfConnector { 224 225 callBackURL := fmt.Sprintf("%s/callback", serverURL) 226 227 testConfig := Config{ 228 APIURL: serverURL, 229 ClientID: "test-client", 230 ClientSecret: "secret", 231 RedirectURI: callBackURL, 232 InsecureSkipVerify: true, 233 } 234 235 log := logrus.New() 236 237 conn, err := testConfig.Open("id", log) 238 if err != nil { 239 t.Fatal(err) 240 } 241 242 cfConn, ok := conn.(*cfConnector) 243 if !ok { 244 t.Fatal(errors.New("it is not a cf conn")) 245 } 246 247 return cfConn 248} 249 250func expectEqual(t *testing.T, a interface{}, b interface{}) { 251 if !reflect.DeepEqual(a, b) { 252 t.Fatalf("Expected %+v to equal %+v", a, b) 253 } 254} 255 256func expectNotEqual(t *testing.T, a interface{}, b interface{}) { 257 if reflect.DeepEqual(a, b) { 258 t.Fatalf("Expected %+v to NOT equal %+v", a, b) 259 } 260} 261