github.com/DaAlbrecht/cf-cli@v0.0.0-20231128151943-1fe19bb400b9/integration/helpers/fake_server.go (about)

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