github.com/loafoe/cli@v7.1.0+incompatible/integration/helpers/fake_server.go (about) 1 package helpers 2 3 import ( 4 "fmt" 5 "net/http" 6 "strings" 7 "time" 8 9 . "github.com/onsi/gomega" 10 . "github.com/onsi/gomega/gexec" 11 . "github.com/onsi/gomega/ghttp" 12 ) 13 14 const ( 15 DefaultV2Version string = "2.131.0" 16 DefaultV3Version string = "3.66.0" 17 DefaultAuthorizationPath string = "" 18 ) 19 20 // StartAndTargetMockServerWithAPIVersions starts and targets a server with the given V2 and V3 21 // API versions. 22 func StartAndTargetMockServerWithAPIVersions(v2Version string, v3Version string) *Server { 23 server := StartMockServerWithAPIVersions(v2Version, v3Version) 24 Eventually(CF("api", server.URL(), "--skip-ssl-validation")).Should(Exit(0)) 25 26 return server 27 } 28 29 // StartMockServerWithMinimumCLIVersion starts a server with the default V2 and V3 30 // API versions and the given minimum CLI version. 31 func StartMockServerWithMinimumCLIVersion(minCLIVersion string) *Server { 32 return startServerWithVersions(DefaultV2Version, DefaultV3Version, &minCLIVersion, DefaultAuthorizationPath) 33 } 34 35 // StartMockServerWithAPIVersions starts a server with the given V2 and V3 36 // API versions 37 func StartMockServerWithAPIVersions(v2Version string, v3Version string) *Server { 38 return startServerWithVersions(v2Version, v3Version, nil, DefaultAuthorizationPath) 39 } 40 41 // StartMockServerWithAPIVersions starts a server with the given V2 and V3 42 // API versions 43 func StartMockServerWithCustomAuthorizationEndpoint(authorizationPath string) *Server { 44 return startServerWithVersions(DefaultV2Version, DefaultV3Version, nil, authorizationPath) 45 } 46 47 func startServerWithVersions(v2Version string, v3Version string, minimumCLIVersion *string, authorizationPath string) *Server { 48 server := NewTLSServer() 49 50 rootResponse := fmt.Sprintf(`{ 51 "links": { 52 "self": { 53 "href": "%[1]s" 54 }, 55 "cloud_controller_v2": { 56 "href": "%[1]s/v2", 57 "meta": { 58 "version": "%[2]s" 59 } 60 }, 61 "cloud_controller_v3": { 62 "href": "%[1]s/v3", 63 "meta": { 64 "version": "%[3]s" 65 } 66 }, 67 "network_policy_v0": { 68 "href": "%[1]s/networking/v0/external" 69 }, 70 "network_policy_v1": { 71 "href": "%[1]s/networking/v1/external" 72 }, 73 "uaa": { 74 "href": "SHOULD-NOT-BE-USED-FOR-LOGGING-IN.com" 75 }, 76 "login": { 77 "href": "%[1]s" 78 }, 79 "logging": { 80 "href": "wss://unused:443" 81 }, 82 "log_cache": { 83 "href": "%[1]s" 84 }, 85 "app_ssh": { 86 "href": "unused:2222", 87 "meta": { 88 "host_key_fingerprint": "unused", 89 "oauth_client": "ssh-proxy" 90 } 91 } 92 } 93 }`, server.URL(), v2Version, v3Version) 94 95 v2InfoResponse := struct { 96 APIVersion string `json:"api_version"` 97 AuthorizationEndpoint string `json:"authorization_endpoint"` 98 MinCLIVersion *string `json:"min_cli_version"` 99 }{ 100 APIVersion: v2Version, 101 AuthorizationEndpoint: server.URL() + authorizationPath, 102 MinCLIVersion: minimumCLIVersion} 103 104 server.RouteToHandler(http.MethodGet, "/v2/info", RespondWithJSONEncoded(http.StatusOK, v2InfoResponse)) 105 106 v3Response := strings.Replace(`{"links": { 107 "apps": { 108 "href": "SERVER_URL/v3/apps" 109 }, 110 "organizations": { 111 "href": "SERVER_URL/v3/organizations" 112 }, 113 "spaces": { 114 "href": "SERVER_URL/v3/spaces" 115 } 116 }}`, "SERVER_URL", server.URL(), -1) 117 118 server.RouteToHandler(http.MethodGet, "/v3", func(res http.ResponseWriter, req *http.Request) { 119 res.WriteHeader(http.StatusOK) 120 res.Write([]byte(v3Response)) 121 }) 122 123 server.RouteToHandler(http.MethodGet, authorizationPath+"/login", func(res http.ResponseWriter, req *http.Request) { 124 res.WriteHeader(http.StatusOK) 125 res.Write([]byte(`{"links":{}}`)) 126 }) 127 128 server.RouteToHandler(http.MethodGet, "/", func(res http.ResponseWriter, req *http.Request) { 129 res.WriteHeader(http.StatusOK) 130 res.Write([]byte(rootResponse)) 131 }) 132 133 return server 134 } 135 136 // AddMfa adds a mock handler to the given server which returns a login response and a 200 status code 137 // on GET requests to the /login endpoint. It adds another mock handler to validate the given password and MFA token 138 // upon POST requests to /oauth/token. 139 func AddMfa(server *Server, password string, mfaToken string) { 140 getLoginResponse := fmt.Sprintf(`{ 141 "app": { 142 "version": "4.28.0" 143 }, 144 "showLoginLinks": true, 145 "links": { 146 "uaa": "%[1]s", 147 "passwd": "/forgot_password", 148 "login": "%[1]s", 149 "register": "/create_account" 150 }, 151 "zone_name": "uaa", 152 "entityID": "some-host-name.example.com", 153 "commit_id": "8917980", 154 "idpDefinitions": {}, 155 "prompts": { 156 "username": [ 157 "text", 158 "Email" 159 ], 160 "password": [ 161 "password", 162 "Password" 163 ], 164 "passcode": [ 165 "password", 166 "Temporary Authentication Code ( Get one at %[1]s/passcode )" 167 ], 168 "mfaCode": [ 169 "password", 170 "MFA Code ( Register at %[1]s )" 171 ] 172 }, 173 "timestamp": "2019-02-19T18:08:02+0000" 174 }`, server.URL()) 175 176 server.RouteToHandler(http.MethodGet, "/login", 177 RespondWith(http.StatusOK, getLoginResponse), 178 ) 179 180 server.RouteToHandler(http.MethodPost, "/oauth/token", makeMFAValidator(password, mfaToken)) 181 182 } 183 184 func makeMFAValidator(password string, mfaToken string) http.HandlerFunc { 185 return func(res http.ResponseWriter, req *http.Request) { 186 Expect(req.ParseForm()).To(Succeed()) 187 rightPassword := len(req.Form["password"]) == 1 && req.Form["password"][0] == password 188 rightCode := len(req.Form["mfaCode"]) == 1 && req.Form["mfaCode"][0] == mfaToken 189 190 if rightPassword && rightCode { 191 res.WriteHeader(http.StatusOK) 192 res.Write([]byte(`{ 193 "access_token": "some-access-token", 194 "token_type": "bearer", 195 "id_token": "some-id-token", 196 "refresh_token": "some-refresh-token", 197 "expires_in": 599, 198 "scope": "openid routing.router_groups.write scim.read cloud_controller.admin uaa.user routing.router_groups.read cloud_controller.read password.write cloud_controller.write network.admin doppler.firehose scim.write", 199 "jti": "66e46003f28e44c8a6582f6d6e44753f" 200 }`)) 201 return 202 } 203 res.WriteHeader(http.StatusUnauthorized) 204 } 205 } 206 207 // AddLoginRoutes adds a mock handler to the given server which returns an access token and a 200 status code 208 // on POST requests to /oauth/token. 209 func AddLoginRoutes(s *Server) { 210 s.RouteToHandler("POST", "/oauth/token", RespondWith(http.StatusOK, 211 fmt.Sprintf(`{ 212 "access_token": "%s", 213 "expires_in": 599, 214 "id_token": "some-other-token", 215 "jti": "some-other-string", 216 "refresh_token": "some-refresh-token", 217 "scope": "openid routing.router_groups.write scim.read cloud_controller.admin uaa.user routing.router_groups.read cloud_controller.read password.write cloud_controller.write network.admin doppler.firehose scim.write", 218 "token_type": "bearer" 219 }`, BuildTokenString(time.Now().Add(599*time.Second)))), 220 ) 221 }