diff --git a/admin/api.go b/admin/api.go index bb805803..2b51672d 100644 --- a/admin/api.go +++ b/admin/api.go @@ -69,10 +69,15 @@ func errorMaker(typ string, desc string, code int) func(internal error) Error { var ( ErrorMissingClient = errorMaker("bad_request", "The 'client' cannot be empty", http.StatusBadRequest)(nil) - // Called when oidc.ClientMetadata.Valid() fails. ErrorInvalidClientFunc = errorMaker("bad_request", "Your client could not be validated.", http.StatusBadRequest) errorMap = map[error]func(error) Error{ + client.ErrorMissingRedirectURI: errorMaker("bad_request", "Non-public clients must have at least one redirect URI", http.StatusBadRequest), + + client.ErrorPublicClientRedirectURIs: errorMaker("bad_request", "Public clients cannot specify redirect URIs", http.StatusBadRequest), + + client.ErrorPublicClientMissingName: errorMaker("bad_request", "Public clients require a ClientName", http.StatusBadRequest), + user.ErrorNotFound: errorMaker("resource_not_found", "Resource could not be found.", http.StatusNotFound), user.ErrorDuplicateEmail: errorMaker("bad_request", "Email already in use.", http.StatusBadRequest), user.ErrorInvalidEmail: errorMaker("bad_request", "invalid email.", http.StatusBadRequest), @@ -86,7 +91,6 @@ var ( func (a *AdminAPI) GetAdmin(id string) (adminschema.Admin, error) { usr, err := a.userRepo.Get(nil, id) - if err != nil { return adminschema.Admin{}, mapError(err) } @@ -136,15 +140,9 @@ func (a *AdminAPI) CreateClient(req adminschema.ClientCreateRequest) (adminschem return adminschema.ClientCreateResponse{}, mapError(err) } - if err := cli.Metadata.Valid(); err != nil { - return adminschema.ClientCreateResponse{}, ErrorInvalidClientFunc(err) - } - - // metadata is guaranteed to have at least one redirect_uri by earlier validation. creds, err := a.clientManager.New(cli, &clientmanager.ClientOptions{ TrustedPeers: req.Client.TrustedPeers, }) - if err != nil { return adminschema.ClientCreateResponse{}, mapError(err) } @@ -165,6 +163,12 @@ func (a *AdminAPI) GetConnectors() ([]connector.ConnectorConfig, error) { } func mapError(e error) error { + switch t := e.(type) { + case client.ValidationError: + return ErrorInvalidClientFunc(t) + default: + } + if mapped, ok := errorMap[e]; ok { return mapped(e) } diff --git a/integration/admin_api_test.go b/integration/admin_api_test.go index ef51b06a..4fc7ac30 100644 --- a/integration/admin_api_test.go +++ b/integration/admin_api_test.go @@ -383,7 +383,11 @@ func TestCreateClient(t *testing.T) { } addIDAndSecret := func(cli adminschema.Client) *adminschema.Client { - cli.Id = "client_auth.example.com" + if cli.Public { + cli.Id = "client_" + cli.ClientName + } else { + cli.Id = "client_auth.example.com" + } cli.Secret = base64.URLEncoding.EncodeToString([]byte("client_0")) return &cli } @@ -400,6 +404,23 @@ func TestCreateClient(t *testing.T) { }, } + clientPublicGood := clientGood + clientPublicGood.Public = true + clientPublicGood.Metadata.ClientName = "PublicName" + clientPublicGood.Metadata.RedirectURIs = []url.URL{} + clientPublicGood.Credentials.ID = "client_PublicName" + + adminPublicClientGood := adminClientGood + adminPublicClientGood.Public = true + adminPublicClientGood.ClientName = "PublicName" + adminPublicClientGood.RedirectURIs = []string{} + + adminPublicClientMissingName := adminPublicClientGood + adminPublicClientMissingName.ClientName = "" + + adminPublicClientHasARedirect := adminPublicClientGood + adminPublicClientHasARedirect.RedirectURIs = []string{"https://auth.example.com/"} + adminAdminClient := adminClientGood adminAdminClient.IsAdmin = true clientGoodAdmin := clientGood @@ -479,6 +500,27 @@ func TestCreateClient(t *testing.T) { wantClient: clientGood, wantTrustedPeers: []string{"test_client_0"}, }, + { + req: adminschema.ClientCreateRequest{ + Client: &adminPublicClientGood, + }, + want: adminschema.ClientCreateResponse{ + Client: addIDAndSecret(adminPublicClientGood), + }, + wantClient: clientPublicGood, + }, + { + req: adminschema.ClientCreateRequest{ + Client: &adminPublicClientMissingName, + }, + wantError: http.StatusBadRequest, + }, + { + req: adminschema.ClientCreateRequest{ + Client: &adminPublicClientHasARedirect, + }, + wantError: http.StatusBadRequest, + }, } for i, tt := range tests { @@ -530,6 +572,7 @@ func TestCreateClient(t *testing.T) { repoClient, err := f.cr.Get(nil, resp.Client.Id) if err != nil { t.Errorf("case %d: Unexpected error getting client: %v", i, err) + continue } if diff := pretty.Compare(tt.wantClient, repoClient); diff != "" { diff --git a/schema/adminschema/mapper.go b/schema/adminschema/mapper.go index f360750a..d116742d 100644 --- a/schema/adminschema/mapper.go +++ b/schema/adminschema/mapper.go @@ -24,6 +24,7 @@ func MapSchemaClientToClient(sc Client) (client.Client, error) { Metadata: oidc.ClientMetadata{ RedirectURIs: make([]url.URL, len(sc.RedirectURIs)), }, + Public: sc.Public, } for i, ru := range sc.RedirectURIs { if ru == "" { @@ -65,6 +66,8 @@ func MapClientToSchemaClient(c client.Client) Client { Id: c.Credentials.ID, Secret: c.Credentials.Secret, RedirectURIs: make([]string, len(c.Metadata.RedirectURIs)), + IsAdmin: c.Admin, + Public: c.Public, } for i, u := range c.Metadata.RedirectURIs { cl.RedirectURIs[i] = u.String() @@ -78,6 +81,5 @@ func MapClientToSchemaClient(c client.Client) Client { if c.Metadata.ClientURI != nil { cl.ClientURI = c.Metadata.ClientURI.String() } - cl.IsAdmin = c.Admin return cl } diff --git a/schema/adminschema/mapper_test.go b/schema/adminschema/mapper_test.go index e1b17b32..5ce2a115 100644 --- a/schema/adminschema/mapper_test.go +++ b/schema/adminschema/mapper_test.go @@ -43,6 +43,23 @@ func TestMapSchemaClientToClient(t *testing.T) { ClientURI: mustParseURL(t, "https://clientURI.example.com"), }, }, + }, { + sc: Client{ + Id: "456", + Secret: "sec_456", + ClientName: "Dave", + Public: true, + }, + want: client.Client{ + Credentials: oidc.ClientCredentials{ + ID: "456", + Secret: "sec_456", + }, + Metadata: oidc.ClientMetadata{ + ClientName: "Dave", + }, + Public: true, + }, }, { sc: Client{ Id: "123", @@ -108,6 +125,24 @@ func TestMapClientToClientSchema(t *testing.T) { }, }, }, + { + want: Client{ + Id: "456", + Secret: "sec_456", + ClientName: "Dave", + Public: true, + }, + c: client.Client{ + Credentials: oidc.ClientCredentials{ + ID: "456", + Secret: "sec_456", + }, + Metadata: oidc.ClientMetadata{ + ClientName: "Dave", + }, + Public: true, + }, + }, } for i, tt := range tests {