forked from mystiq/dex
95757e8779
This is instead of oidc.ClientIdentity. This makes it easier to add new fields custom to dex to the client.
109 lines
3.1 KiB
Go
109 lines
3.1 KiB
Go
package client
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"io"
|
|
"net/url"
|
|
"reflect"
|
|
|
|
"github.com/coreos/go-oidc/oidc"
|
|
)
|
|
|
|
var (
|
|
ErrorInvalidRedirectURL = errors.New("not a valid redirect url for the given client")
|
|
ErrorCantChooseRedirectURL = errors.New("must provide a redirect url; client has many")
|
|
ErrorNoValidRedirectURLs = errors.New("no valid redirect URLs for this client.")
|
|
ErrorNotFound = errors.New("no data found")
|
|
)
|
|
|
|
type Client struct {
|
|
Credentials oidc.ClientCredentials
|
|
Metadata oidc.ClientMetadata
|
|
Admin bool
|
|
}
|
|
|
|
type ClientIdentityRepo interface {
|
|
Get(clientID string) (Client, error)
|
|
|
|
// Metadata returns one matching ClientMetadata if the given client
|
|
// exists, otherwise nil. The returned error will be non-nil only
|
|
// if the repo was unable to determine client existence.
|
|
Metadata(clientID string) (*oidc.ClientMetadata, error)
|
|
|
|
// Authenticate asserts that a client with the given ID exists and
|
|
// that the provided secret matches. If either of these assertions
|
|
// fail, (false, nil) will be returned. Only if the repo is unable
|
|
// to make these assertions will a non-nil error be returned.
|
|
Authenticate(creds oidc.ClientCredentials) (bool, error)
|
|
|
|
// All returns all registered Client Identities.
|
|
All() ([]Client, error)
|
|
|
|
// New registers a ClientIdentity with the repo for the given metadata.
|
|
// An unused ID must be provided. A corresponding secret will be returned
|
|
// in a ClientCredentials struct along with the provided ID.
|
|
New(client Client) (*oidc.ClientCredentials, error)
|
|
|
|
SetDexAdmin(clientID string, isAdmin bool) error
|
|
|
|
IsDexAdmin(clientID string) (bool, error)
|
|
}
|
|
|
|
// ValidRedirectURL returns the passed in URL if it is present in the redirectURLs list, and returns an error otherwise.
|
|
// If nil is passed in as the rURL and there is only one URL in redirectURLs,
|
|
// that URL will be returned. If nil is passed but theres >1 URL in the slice,
|
|
// then an error is returned.
|
|
func ValidRedirectURL(rURL *url.URL, redirectURLs []url.URL) (url.URL, error) {
|
|
if len(redirectURLs) == 0 {
|
|
return url.URL{}, ErrorNoValidRedirectURLs
|
|
}
|
|
|
|
if rURL == nil {
|
|
if len(redirectURLs) > 1 {
|
|
return url.URL{}, ErrorCantChooseRedirectURL
|
|
}
|
|
|
|
return redirectURLs[0], nil
|
|
}
|
|
|
|
for _, ru := range redirectURLs {
|
|
if reflect.DeepEqual(ru, *rURL) {
|
|
return ru, nil
|
|
}
|
|
}
|
|
return url.URL{}, ErrorInvalidRedirectURL
|
|
}
|
|
|
|
func ClientsFromReader(r io.Reader) ([]Client, error) {
|
|
var c []struct {
|
|
ID string `json:"id"`
|
|
Secret string `json:"secret"`
|
|
RedirectURLs []string `json:"redirectURLs"`
|
|
}
|
|
if err := json.NewDecoder(r).Decode(&c); err != nil {
|
|
return nil, err
|
|
}
|
|
clients := make([]Client, len(c))
|
|
for i, client := range c {
|
|
redirectURIs := make([]url.URL, len(client.RedirectURLs))
|
|
for j, u := range client.RedirectURLs {
|
|
uri, err := url.Parse(u)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
redirectURIs[j] = *uri
|
|
}
|
|
|
|
clients[i] = Client{
|
|
Credentials: oidc.ClientCredentials{
|
|
ID: client.ID,
|
|
Secret: client.Secret,
|
|
},
|
|
Metadata: oidc.ClientMetadata{
|
|
RedirectURIs: redirectURIs,
|
|
},
|
|
}
|
|
}
|
|
return clients, nil
|
|
}
|