Commit c0668997 authored by Bobby Rullo's avatar Bobby Rullo

admin: create public clients with admin api

parent ff933812
......@@ -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)
}
......
......@@ -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 != "" {
......
......@@ -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
}
......@@ -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 {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment