...

Source file src/edge-infra.dev/pkg/edge/okta/faker.go

Documentation: edge-infra.dev/pkg/edge/okta

     1  package okta
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	"net/http/httptest"
     7  	"net/url"
     8  	"strings"
     9  	"time"
    10  
    11  	"edge-infra.dev/pkg/edge/api/types"
    12  	"edge-infra.dev/pkg/edge/api/utils"
    13  )
    14  
    15  const (
    16  	oktaIntrospectionPath = "/v1/introspect?client_id=%s"
    17  	oktaUserInfoPath      = "/v1/userinfo"
    18  	oktaTokenRefreshPath  = "/v1/token"
    19  	badOktaToken          = "bad-okta-token"     //nolint:gosec
    20  	invalidOktaToken      = "invalid-okta-token" //nolint:gosec
    21  )
    22  
    23  func MockServer(cfg *types.OktaConfig) *httptest.Server {
    24  	server := utils.NewMockHTTPTestServer().AddAllowedContentType(formContentType, jsonContentType).DefaultNotFound()
    25  	// Okta Introspection API mock
    26  	server.Post("Okta Introspection", fmt.Sprintf(oktaIntrospectionPath, cfg.ClientID), func(w http.ResponseWriter, r *http.Request) {
    27  		requestBody := make(map[string]string)
    28  		err := utils.ReadRequestBody(r, requestBody)
    29  		if err != nil {
    30  			panic(err)
    31  		}
    32  		if _, exists := requestBody["token"]; !exists || requestBody["token"] == badOktaToken {
    33  			utils.WriteCustomResponse(w, http.StatusUnauthorized, []byte("Invalid Credentials"))
    34  		} else if _, exists := requestBody["token"]; !exists || requestBody["token"] == invalidOktaToken {
    35  			response := MockIntrospectionInactiveResponse(server.Server.URL, cfg.ClientID)
    36  			utils.WriteJSON(w, response)
    37  		} else {
    38  			response := MockIntrospectionResponse(server.Server.URL, cfg.ClientID)
    39  			utils.WriteJSON(w, response)
    40  		}
    41  	}, func(_ http.ResponseWriter, r *http.Request) bool {
    42  		queries, err := url.ParseQuery(r.URL.RawQuery)
    43  		if err != nil {
    44  			return false
    45  		}
    46  		val, exists := queries["client_id"]
    47  		if exists {
    48  			return val[0] == cfg.ClientID
    49  		}
    50  		return exists
    51  	})
    52  	// Okta UserInfo API mock
    53  	server.Get("Okta UserInfo", oktaUserInfoPath, func(w http.ResponseWriter, r *http.Request) {
    54  		if _, exists := r.Header["Authorization"]; !exists || strings.Contains(r.Header["Authorization"][0], badOktaToken) {
    55  			utils.WriteCustomResponse(w, http.StatusUnauthorized, []byte("Invalid Credentials"))
    56  		} else {
    57  			response := MockUserInfoResponse()
    58  			utils.WriteJSON(w, response)
    59  		}
    60  	}, func(_ http.ResponseWriter, r *http.Request) bool {
    61  		return r.Method == http.MethodGet
    62  	})
    63  	server.Post("Okta Token Refresh", oktaTokenRefreshPath, func(w http.ResponseWriter, _ *http.Request) {
    64  		response := MockTokenRefreshResponse()
    65  		utils.WriteJSON(w, response)
    66  	}, func(_ http.ResponseWriter, r *http.Request) bool {
    67  		return r.Method == http.MethodPost && strings.Contains(r.RequestURI, oktaTokenRefreshPath)
    68  	})
    69  	cfg.OktaIssuer = server.Server.URL
    70  	return server.Server
    71  }
    72  
    73  func MockIntrospectionResponse(issuer, clientID string) *IntrospectionResponse {
    74  	currentTime := time.Now()
    75  	return &IntrospectionResponse{
    76  		Active:    true,
    77  		Scope:     "profile email openid",
    78  		Username:  "test-user",
    79  		Expires:   int(currentTime.Add(15 * time.Minute).UnixNano()),
    80  		IssuedAt:  int(currentTime.UnixNano()),
    81  		Sub:       "test@ncr.com",
    82  		Aud:       "api://default",
    83  		Issuer:    issuer,
    84  		Jti:       "AT.IR2_7zD62pLUDqsddXeccrcpf98LvhjnsqKlsIgnXcNFFK2s",
    85  		TokenType: "Bearer",
    86  		ClientID:  clientID,
    87  		UID:       "vguhjsbxvksbwvdid",
    88  		Groups:    []string{"Everyone"},
    89  		Type:      "user",
    90  		Email:     "test@ncr.com",
    91  	}
    92  }
    93  
    94  func MockIntrospectionInactiveResponse(issuer, clientID string) *IntrospectionResponse {
    95  	currentTime := time.Now()
    96  	return &IntrospectionResponse{
    97  		Active:    false,
    98  		Scope:     "profile email openid",
    99  		Username:  "test-user",
   100  		Expires:   int(currentTime.Add(15 * time.Minute).UnixNano()),
   101  		IssuedAt:  int(currentTime.UnixNano()),
   102  		Sub:       "test@ncr.com",
   103  		Aud:       "api://default",
   104  		Issuer:    issuer,
   105  		Jti:       "AT.IR2_7zD62pLUDqsddXeccrcpf98LvhjnsqKlsIgnXcNFFK2s",
   106  		TokenType: "Bearer",
   107  		ClientID:  clientID,
   108  		UID:       "vguhjsbxvksbwvdid",
   109  		Groups:    []string{"Everyone"},
   110  		Type:      "user",
   111  		Email:     "test@ncr.com",
   112  	}
   113  }
   114  
   115  func MockUserInfoResponse() *UserInfo {
   116  	return &UserInfo{
   117  		Sub:               "test@ncr.com",
   118  		Name:              "John Doe",
   119  		Locale:            "en_US",
   120  		Email:             "test@ncr.com",
   121  		PreferredUsername: "test@ncr.com",
   122  		GivenName:         "John",
   123  		FamilyName:        "Doe",
   124  		ZoneInfo:          "America/Los_Angeles",
   125  		EmailVerified:     true,
   126  	}
   127  }
   128  
   129  func MockTokenRefreshResponse() *RefreshResponse {
   130  	return &RefreshResponse{
   131  		TokenType:    "refresh-token",
   132  		ExpiresIn:    float64(15 * time.Minute),
   133  		AccessToken:  "good-okta-token",
   134  		Scope:        "offline_access openid",
   135  		RefreshToken: "refresh-token",
   136  		IDToken:      "id-token",
   137  	}
   138  }
   139  

View as plain text