Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion internal/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,6 @@ func NewAPIWithVersion(globalConfig *conf.GlobalConfiguration, db *storage.Conne
})
})
})

})
})

Expand Down
1 change: 1 addition & 0 deletions internal/api/apierrors/errorcode.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ const (
ErrorCodeSAMLAssertionNoEmail ErrorCode = "saml_assertion_no_email"
ErrorCodeUserAlreadyExists ErrorCode = "user_already_exists"
ErrorCodeSSOProviderNotFound ErrorCode = "sso_provider_not_found"
ErrorCodeSSOProviderDisabled ErrorCode = "sso_provider_disabled"
ErrorCodeSAMLMetadataFetchFailed ErrorCode = "saml_metadata_fetch_failed"
ErrorCodeSAMLIdPAlreadyExists ErrorCode = "saml_idp_already_exists"
ErrorCodeSSODomainAlreadyExists ErrorCode = "sso_domain_already_exists"
Expand Down
12 changes: 12 additions & 0 deletions internal/api/samlacs.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,12 @@ func (a *API) handleSamlAcs(w http.ResponseWriter, r *http.Request) error {
return apierrors.NewInternalServerError("Unable to find SSO Provider from SAML RelayState")
}

if !ssoProvider.IsEnabled() {
return apierrors.NewNotFoundError(
apierrors.ErrorCodeSSOProviderDisabled,
"SSO Provider assigned for this domain is currently disabled")
}

initiatedBy = "sp"
entityId = ssoProvider.SAMLProvider.EntityID
redirectTo = relayState.RedirectTo
Expand Down Expand Up @@ -156,6 +162,12 @@ func (a *API) handleSamlAcs(w http.ResponseWriter, r *http.Request) error {
return err
}

if !ssoProvider.IsEnabled() {
return apierrors.NewNotFoundError(
apierrors.ErrorCodeSSOProviderDisabled,
"SSO Provider assigned for this domain is currently disabled")
}

idpMetadata, err := ssoProvider.SAMLProvider.EntityDescriptor()
if err != nil {
return err
Expand Down
40 changes: 23 additions & 17 deletions internal/api/sso.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,25 +52,8 @@ func (a *API) SingleSignOn(w http.ResponseWriter, r *http.Request) error {
if hasProviderID, err = params.validate(); err != nil {
return err
}
codeChallengeMethod := params.CodeChallengeMethod
codeChallenge := params.CodeChallenge

if err := validatePKCEParams(codeChallengeMethod, codeChallenge); err != nil {
return err
}
flowType := getFlowFromChallenge(params.CodeChallenge)
var flowStateID *uuid.UUID
flowStateID = nil
if isPKCEFlow(flowType) {
flowState, err := generateFlowState(db, models.SSOSAML.String(), models.SSOSAML, codeChallengeMethod, codeChallenge, nil)
if err != nil {
return err
}
flowStateID = &flowState.ID
}

var ssoProvider *models.SSOProvider

if hasProviderID {
ssoProvider, err = models.FindSSOProviderByID(db, params.ProviderID)
if models.IsNotFoundError(err) {
Expand All @@ -87,6 +70,29 @@ func (a *API) SingleSignOn(w http.ResponseWriter, r *http.Request) error {
}
}

if !ssoProvider.IsEnabled() {
return apierrors.NewNotFoundError(
apierrors.ErrorCodeSSOProviderDisabled,
"SSO Provider is currently disabled")
}

codeChallengeMethod := params.CodeChallengeMethod
codeChallenge := params.CodeChallenge

if err := validatePKCEParams(codeChallengeMethod, codeChallenge); err != nil {
return err
}
flowType := getFlowFromChallenge(params.CodeChallenge)
var flowStateID *uuid.UUID
flowStateID = nil
if isPKCEFlow(flowType) {
flowState, err := generateFlowState(db, models.SSOSAML.String(), models.SSOSAML, codeChallengeMethod, codeChallenge, nil)
if err != nil {
return err
}
flowStateID = &flowState.ID
}

entityDescriptor, err := ssoProvider.SAMLProvider.EntityDescriptor()
if err != nil {
return apierrors.NewInternalServerError("Error parsing SAML Metadata for SAML provider").WithInternalError(err)
Expand Down
66 changes: 53 additions & 13 deletions internal/api/ssoadmin.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,32 @@ import (
"github.com/supabase/auth/internal/utilities"
)

// loadSSOProvider looks for an idp_id parameter in the URL route and loads the SSO provider
// with that ID (or resource ID) and adds it to the context.
// loadSSOProvider looks for an idp_id and first checks it for a "resource_"
// prefix, if present the provider is loaded by resource_id. Otherwise the
// provider is loaded by id.
func (a *API) loadSSOProvider(w http.ResponseWriter, r *http.Request) (context.Context, error) {
ctx := r.Context()
db := a.db.WithContext(ctx)

idpParam := chi.URLParam(r, "idp_id")
var (
provider *models.SSOProvider
err error
)

idpID, err := uuid.FromString(idpParam)
if err != nil {
// idpParam is not UUIDv4
return nil, apierrors.NewNotFoundError(apierrors.ErrorCodeSSOProviderNotFound, "SSO Identity Provider not found")
const resourcePrefix = "resource_"
idpParam := chi.URLParam(r, "idp_id")
switch {
case strings.HasPrefix(idpParam, resourcePrefix):
resourceID := strings.TrimPrefix(idpParam, resourcePrefix)
provider, err = models.FindSSOProviderByResourceID(db, resourceID)
default:
idpID, idpErr := uuid.FromString(idpParam)
if idpErr != nil {
return nil, apierrors.NewNotFoundError(apierrors.ErrorCodeSSOProviderNotFound, "SSO Identity Provider not found")
}
provider, err = models.FindSSOProviderByID(db, idpID)
}

// idpParam is a UUIDv4
provider, err := models.FindSSOProviderByID(db, idpID)
if err != nil {
if models.IsNotFoundError(err) {
return nil, apierrors.NewNotFoundError(apierrors.ErrorCodeSSOProviderNotFound, "SSO Identity Provider not found")
Expand All @@ -44,17 +54,16 @@ func (a *API) loadSSOProvider(w http.ResponseWriter, r *http.Request) (context.C
}

observability.LogEntrySetField(r, "sso_provider_id", provider.ID.String())

return withSSOProvider(r.Context(), provider), nil
}

// adminSSOProvidersList lists all SAML SSO Identity Providers in the system. Does
// adminSSOProvidersList lists all SSO Identity Providers in the system. Does
// not deal with pagination at this time.
func (a *API) adminSSOProvidersList(w http.ResponseWriter, r *http.Request) error {
ctx := r.Context()
db := a.db.WithContext(ctx)

providers, err := models.FindAllSAMLProviders(db)
providers, err := models.FindAllSSOProvidersByFilter(db, r.URL.Query())
if err != nil {
return err
}
Expand All @@ -77,6 +86,9 @@ type CreateSSOProviderParams struct {
Domains []string `json:"domains"`
AttributeMapping models.SAMLAttributeMapping `json:"attribute_mapping"`
NameIDFormat string `json:"name_id_format"`

ResourceID *string `json:"resource_id,omitempty"`
Disabled *bool `json:"disabled,omitempty"`
}

func (p *CreateSSOProviderParams) validate(forUpdate bool) error {
Expand Down Expand Up @@ -223,17 +235,23 @@ func (a *API) adminSSOProvidersCreate(w http.ResponseWriter, r *http.Request) er
}

provider := &models.SSOProvider{

// TODO handle Name, Description, Attribute Mapping
SAMLProvider: models.SAMLProvider{
EntityID: metadata.EntityID,
MetadataXML: string(rawMetadata),
},
}

if params.ResourceID != nil {
provider.ResourceID = params.ResourceID
}
if params.Disabled != nil {
provider.Disabled = params.Disabled
}
if params.MetadataURL != "" {
provider.SAMLProvider.MetadataURL = &params.MetadataURL
}

if params.NameIDFormat != "" {
provider.SAMLProvider.NameIDFormat = &params.NameIDFormat
}
Expand Down Expand Up @@ -374,6 +392,28 @@ func (a *API) adminSSOProvidersUpdate(w http.ResponseWriter, r *http.Request) er
}
}

if params.ResourceID != nil {
resourceID := *params.ResourceID
switch {
case resourceID == "" && provider.ResourceID != nil:
provider.ResourceID = nil
modified = true
case resourceID != "" &&
(provider.ResourceID == nil ||
*provider.ResourceID != resourceID):
provider.ResourceID = &resourceID
modified = true
}
}

if params.Disabled != nil {
disabled := *params.Disabled
if provider.Disabled == nil || *provider.Disabled != disabled {
provider.Disabled = &disabled
modified = true
}
}

if modified {
if err := db.Transaction(func(tx *storage.Connection) error {
if terr := tx.Eager().Update(provider); terr != nil {
Expand Down
Loading