Skip to content
This repository has been archived by the owner on Sep 25, 2024. It is now read-only.

Commit

Permalink
Implement /admin/sso/providers endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
kwoodhouse93 committed Nov 7, 2022
1 parent 8feb4de commit 9b06acb
Show file tree
Hide file tree
Showing 4 changed files with 285 additions and 47 deletions.
48 changes: 1 addition & 47 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,53 +20,7 @@ This library is a pre-release work in progress. It has not been thoroughly teste

The endpoints for SSO SAML are not tested and `POST /sso/saml/acs` does not provide request and response types. If you need additional support for SSO SAML, please create an issue or a pull request.

Required for V1 release:
- Implement and test endpoints
- Client API
- [X] GET /health
- [X] GET /settings
- [X] GET /callback
- [X] POST /callback
- [X] GET /authorize
- [X] POST /invite
- [X] POST /signup
- [X] POST /recover
- [X] POST /magiclink
- [X] POST /otp
- [X] POST /token
- [X] GET /verify
- [X] POST /verify
- [X] POST /logout
- [X] GET /reauthenticate
- [X] GET /user
- [X] PUT /user
- [X] POST /factors
- [X] POST /factors/{factor_id}/verify
- [X] POST /factors/{factor_id}/challenge
- [X] DELETE /factors/{factor_id}
- [X] GET /sso/saml/metadata (not tested)
- [X] POST /sso/saml/acs (not tested)
- Admin API
- [X] GET /admin/audit
- [X] GET /admin/users
- [X] POST /admin/users
- [X] GET /admin/users/{user_id}/factors
- [X] DELETE /admin/users/{user_id}/factors/{factor_id}
- [X] PUT /admin/users/{user_id}/factors/{factor_id}
- [X] GET /admin/users/{user_id}
- [X] PUT /admin/users/{user_id}
- [X] DELETE /admin/users/{user_id}
- [X] POST /admin/generate_link
- [ ] GET /admin/sso/providers
- [ ] POST /admin/sso/providers
- [ ] GET /admin/sso/providers/{idp_id}
- [ ] PUT /admin/sso/providers/{idp_id}
- [ ] DELETE /admin/sso/providers/{idp_id}
- Test infrastructure
- [X] Postgres container with GoTrue config
- [X] GoTrue container - signup enabled, autoconfirm off
- [X] GoTrue container - signup enabled, autoconfirm on
- [X] GoTrue container - signup disabled
Still required for V1 release:
- [ ] Support for Captcha tokens

## Quick start
Expand Down
21 changes: 21 additions & 0 deletions api.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,27 @@ type Client interface {
// Requires admin token.
AdminGenerateLink(req types.AdminGenerateLinkRequest) (*types.AdminGenerateLinkResponse, error)

// GET /admin/sso/providers
//
// Get a list of all SAML SSO Identity Providers in the system.
AdminListSSOProviders() (*types.AdminListSSOProvidersResponse, error)
// POST /admin/sso/providers
//
// Create a new SAML SSO Identity Provider.
AdminCreateSSOProvider(req types.AdminCreateSSOProviderRequest) (*types.AdminCreateSSOProviderResponse, error)
// GET /admin/sso/providers/{idp_id}
//
// Get a SAML SSO Identity Provider by ID.
AdminGetSSOProvider(req types.AdminGetSSOProviderRequest) (*types.AdminGetSSOProviderResponse, error)
// PUT /admin/sso/providers/{idp_id}
//
// Update a SAML SSO Identity Provider by ID.
AdminUpdateSSOProvider(req types.AdminUpdateSSOProviderRequest) (*types.AdminUpdateSSOProviderResponse, error)
// DELETE /admin/sso/providers/{idp_id}
//
// Delete a SAML SSO Identity Provider by ID.
AdminDeleteSSOProvider(req types.AdminDeleteSSOProviderRequest) (*types.AdminDeleteSSOProviderResponse, error)

// POST /admin/users
//
// Creates the user based on the user_id specified.
Expand Down
184 changes: 184 additions & 0 deletions endpoints/adminssoproviders.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
package endpoints

import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"

"github.com/kwoodhouse93/gotrue-go/types"
)

const adminSSOPath = "/admin/sso/providers"

// GET /admin/sso/providers
//
// Get a list of all SAML SSO Identity Providers in the system.
func (c *Client) AdminListSSOProviders() (*types.AdminListSSOProvidersResponse, error) {
r, err := c.newRequest(adminSSOPath, http.MethodGet, nil)
if err != nil {
return nil, err
}

resp, err := c.client.Do(r)
if err != nil {
return nil, err
}
defer resp.Body.Close()

if resp.StatusCode < 200 || resp.StatusCode >= 300 {
fullBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("response status code %d", resp.StatusCode)
}
return nil, fmt.Errorf("response status code %d: %s", resp.StatusCode, fullBody)
}

var res types.AdminListSSOProvidersResponse
err = json.NewDecoder(resp.Body).Decode(&res)
if err != nil {
return nil, err
}

return &res, nil
}

// POST /admin/sso/providers
//
// Create a new SAML SSO Identity Provider.
func (c *Client) AdminCreateSSOProvider(req types.AdminCreateSSOProviderRequest) (*types.AdminCreateSSOProviderResponse, error) {
body, err := json.Marshal(req)
if err != nil {
return nil, err
}

r, err := c.newRequest(adminSSOPath, http.MethodPost, bytes.NewBuffer(body))
if err != nil {
return nil, err
}

resp, err := c.client.Do(r)
if err != nil {
return nil, err
}
defer resp.Body.Close()

if resp.StatusCode < 200 || resp.StatusCode >= 300 {
fullBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("response status code %d", resp.StatusCode)
}
return nil, fmt.Errorf("response status code %d: %s", resp.StatusCode, fullBody)
}

var res types.AdminCreateSSOProviderResponse
err = json.NewDecoder(resp.Body).Decode(&res)
if err != nil {
return nil, err
}

return &res, nil
}

// GET /admin/sso/providers/{idp_id}
//
// Get a SAML SSO Identity Provider by ID.
func (c *Client) AdminGetSSOProvider(req types.AdminGetSSOProviderRequest) (*types.AdminGetSSOProviderResponse, error) {
r, err := c.newRequest(fmt.Sprintf("%s/%s", adminSSOPath, req.ProviderID), http.MethodGet, nil)
if err != nil {
return nil, err
}

resp, err := c.client.Do(r)
if err != nil {
return nil, err
}
defer resp.Body.Close()

if resp.StatusCode < 200 || resp.StatusCode >= 300 {
fullBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("response status code %d", resp.StatusCode)
}
return nil, fmt.Errorf("response status code %d: %s", resp.StatusCode, fullBody)
}

var res types.AdminGetSSOProviderResponse
err = json.NewDecoder(resp.Body).Decode(&res)
if err != nil {
return nil, err
}

return &res, nil
}

// PUT /admin/sso/providers/{idp_id}
//
// Update a SAML SSO Identity Provider by ID.
func (c *Client) AdminUpdateSSOProvider(req types.AdminUpdateSSOProviderRequest) (*types.AdminUpdateSSOProviderResponse, error) {
body, err := json.Marshal(req)
if err != nil {
return nil, err
}

r, err := c.newRequest(fmt.Sprintf("%s/%s", adminSSOPath, req.ProviderID), http.MethodPut, bytes.NewBuffer(body))
if err != nil {
return nil, err
}

resp, err := c.client.Do(r)
if err != nil {
return nil, err
}
defer resp.Body.Close()

if resp.StatusCode < 200 || resp.StatusCode >= 300 {
fullBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("response status code %d", resp.StatusCode)
}
return nil, fmt.Errorf("response status code %d: %s", resp.StatusCode, fullBody)
}

var res types.AdminUpdateSSOProviderResponse
err = json.NewDecoder(resp.Body).Decode(&res)
if err != nil {
return nil, err
}

return &res, nil
}

// DELETE /admin/sso/providers/{idp_id}
//
// Delete a SAML SSO Identity Provider by ID.
func (c *Client) AdminDeleteSSOProvider(req types.AdminDeleteSSOProviderRequest) (*types.AdminDeleteSSOProviderResponse, error) {
path := fmt.Sprintf("%s/%s", adminSSOPath, req.ProviderID)
r, err := c.newRequest(path, http.MethodDelete, nil)
if err != nil {
return nil, err
}

resp, err := c.client.Do(r)
if err != nil {
return nil, err
}
defer resp.Body.Close()

if resp.StatusCode < 200 || resp.StatusCode >= 300 {
fullBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("response status code %d", resp.StatusCode)
}
return nil, fmt.Errorf("response status code %d: %s", resp.StatusCode, fullBody)
}

var res types.AdminDeleteSSOProviderResponse
err = json.NewDecoder(resp.Body).Decode(&res)
if err != nil {
return nil, err
}

return &res, nil
}
79 changes: 79 additions & 0 deletions types/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,85 @@ type AdminDeleteUserFactorRequest struct {
FactorID uuid.UUID
}

type SAMLAttribute struct {
Name string `json:"name,omitempty"`
Names []string `json:"names,omitempty"`
Default interface{} `json:"default,omitempty"`
}

type SAMLAttributeMapping struct {
Keys map[string]SAMLAttribute `json:"keys,omitempty"`
}

type SAMLProvider struct {
EntityID string `json:"entity_id"`
MetadataXML string `json:"metadata_xml,omitempty"`
MetadataURL *string `json:"metadata_url,omitempty"`

AttributeMapping SAMLAttributeMapping `json:"attribute_mapping,omitempty"`
}

type SSODomain struct {
Domain string `db:"domain" json:"domain"`
}

type SSOProvider struct {
ID uuid.UUID `json:"id"`
ResourceID *string `json:"resource_id,omitempty"`
SAMLProvider SAMLProvider `json:"saml,omitempty"`
SSODomains []SSODomain `json:"domains"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}

type AdminListSSOProvidersResponse struct {
Providers []SSOProvider `json:"items"`
}

type AdminCreateSSOProviderRequest struct {
ResourceID string `json:"resource_id"`
Type string `json:"type"`
MetadataURL string `json:"metadata_url"`
MetadataXML string `json:"metadata_xml"`
Domains []string `json:"domains"`
AttributeMapping SAMLAttributeMapping `json:"attribute_mapping"`
}

type AdminCreateSSOProviderResponse struct {
SSOProvider
}

type AdminGetSSOProviderRequest struct {
ProviderID uuid.UUID
}

type AdminGetSSOProviderResponse struct {
SSOProvider
}

type AdminUpdateSSOProviderRequest struct {
ProviderID uuid.UUID `json:"-"`

ResourceID string `json:"resource_id"`
Type string `json:"type"`
MetadataURL string `json:"metadata_url"`
MetadataXML string `json:"metadata_xml"`
Domains []string `json:"domains"`
AttributeMapping SAMLAttributeMapping `json:"attribute_mapping"`
}

type AdminUpdateSSOProviderResponse struct {
SSOProvider
}

type AdminDeleteSSOProviderRequest struct {
ProviderID uuid.UUID
}

type AdminDeleteSSOProviderResponse struct {
SSOProvider
}

type Provider string

const (
Expand Down

0 comments on commit 9b06acb

Please sign in to comment.