feat: add ability for users to convert their password login type to oauth/github login (#8105)

* Currently toggled by experiment flag

---------

Co-authored-by: Bruno Quaresma <bruno@coder.com>
This commit is contained in:
Steven Masley
2023-06-30 08:38:48 -04:00
committed by GitHub
co-authored by Bruno Quaresma
parent 357f3b38f7
commit b5f26d9bdf
50 changed files with 2043 additions and 261 deletions
+3
View File
@@ -23,6 +23,7 @@ const (
ResourceTypeAPIKey ResourceType = "api_key"
ResourceTypeGroup ResourceType = "group"
ResourceTypeLicense ResourceType = "license"
ResourceTypeConvertLogin ResourceType = "convert_login"
)
func (r ResourceType) FriendlyString() string {
@@ -47,6 +48,8 @@ func (r ResourceType) FriendlyString() string {
return "group"
case ResourceTypeLicense:
return "license"
case ResourceTypeConvertLogin:
return "login type conversion"
default:
return "unknown"
}
+4
View File
@@ -1759,6 +1759,10 @@ const (
// only Coordinator
ExperimentTailnetPGCoordinator Experiment = "tailnet_pg_coordinator"
// ExperimentConvertToOIDC enables users to convert from password to
// oidc.
ExperimentConvertToOIDC Experiment = "convert-to-oidc"
// Add new experiments here!
// ExperimentExample Experiment = "example"
)
+41 -3
View File
@@ -93,6 +93,12 @@ type UserRoles struct {
OrganizationRoles map[uuid.UUID][]string `json:"organization_roles"`
}
type ConvertLoginRequest struct {
// ToType is the login type to convert to.
ToType LoginType `json:"to_type" validate:"required"`
Password string `json:"password" validate:"required"`
}
// LoginWithPasswordRequest enables callers to authenticate with email and password.
type LoginWithPasswordRequest struct {
Email string `json:"email" validate:"required,email" format:"email"`
@@ -104,21 +110,33 @@ type LoginWithPasswordResponse struct {
SessionToken string `json:"session_token" validate:"required"`
}
type OAuthConversionResponse struct {
StateString string `json:"state_string"`
ExpiresAt time.Time `json:"expires_at" format:"date-time"`
ToType LoginType `json:"to_type"`
UserID uuid.UUID `json:"user_id" format:"uuid"`
}
type CreateOrganizationRequest struct {
Name string `json:"name" validate:"required,username"`
}
// AuthMethods contains authentication method information like whether they are enabled or not or custom text, etc.
type AuthMethods struct {
Password AuthMethod `json:"password"`
Github AuthMethod `json:"github"`
OIDC OIDCAuthMethod `json:"oidc"`
ConvertToOIDCEnabled bool `json:"convert_to_oidc_enabled"`
Password AuthMethod `json:"password"`
Github AuthMethod `json:"github"`
OIDC OIDCAuthMethod `json:"oidc"`
}
type AuthMethod struct {
Enabled bool `json:"enabled"`
}
type UserLoginType struct {
LoginType LoginType `json:"login_type"`
}
type OIDCAuthMethod struct {
AuthMethod
SignInText string `json:"signInText"`
@@ -299,6 +317,26 @@ func (c *Client) LoginWithPassword(ctx context.Context, req LoginWithPasswordReq
return resp, nil
}
// ConvertLoginType will send a request to convert the user from password
// based authentication to oauth based. The response has the oauth state code
// to use in the oauth flow.
func (c *Client) ConvertLoginType(ctx context.Context, req ConvertLoginRequest) (OAuthConversionResponse, error) {
res, err := c.Request(ctx, http.MethodPost, "/api/v2/users/me/convert-login", req)
if err != nil {
return OAuthConversionResponse{}, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusCreated {
return OAuthConversionResponse{}, ReadBodyAsError(res)
}
var resp OAuthConversionResponse
err = json.NewDecoder(res.Body).Decode(&resp)
if err != nil {
return OAuthConversionResponse{}, err
}
return resp, nil
}
// Logout calls the /logout API
// Call `ClearSessionToken()` to clear the session token of the client.
func (c *Client) Logout(ctx context.Context) error {