Skip to content

Commit

Permalink
sso: add ACL auth-method HTTP API CRUD endpoints (#15338)
Browse files Browse the repository at this point in the history
* core: remove custom auth-method TTLS and use ACL token TTLS.

* agent: add ACL auth-method HTTP endpoints for CRUD actions.

* api: add ACL auth-method client.
  • Loading branch information
jrasell committed Nov 23, 2022
1 parent 1420433 commit 84b79aa
Show file tree
Hide file tree
Showing 8 changed files with 674 additions and 14 deletions.
148 changes: 148 additions & 0 deletions api/acl.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,10 @@ var (
// errMissingACLRoleID is the generic errors to use when a call is missing
// the required ACL Role ID parameter.
errMissingACLRoleID = errors.New("missing ACL role ID")

// errMissingACLAuthMethodName is the generic error to use when a call is
// missing the required ACL auth-method name parameter.
errMissingACLAuthMethodName = errors.New("missing ACL auth-method name")
)

// ACLRoles is used to query the ACL Role endpoints.
Expand Down Expand Up @@ -292,6 +296,76 @@ func (a *ACLRoles) GetByName(roleName string, q *QueryOptions) (*ACLRole, *Query
return &resp, qm, nil
}

// ACLAuthMethods is used to query the ACL auth-methods endpoints.
type ACLAuthMethods struct {
client *Client
}

// ACLAuthMethods returns a new handle on the ACL auth-methods API client.
func (c *Client) ACLAuthMethods() *ACLAuthMethods {
return &ACLAuthMethods{client: c}
}

// List is used to detail all the ACL auth-methods currently stored within
// state.
func (a *ACLAuthMethods) List(q *QueryOptions) ([]*ACLAuthMethodListStub, *QueryMeta, error) {
var resp []*ACLAuthMethodListStub
qm, err := a.client.query("/v1/acl/auth-methods", &resp, q)
if err != nil {
return nil, nil, err
}
return resp, qm, nil
}

// Create is used to create an ACL auth-method.
func (a *ACLAuthMethods) Create(authMethod *ACLAuthMethod, w *WriteOptions) (*WriteMeta, error) {
if authMethod.Name == "" {
return nil, errMissingACLAuthMethodName
}
wm, err := a.client.write("/v1/acl/auth-method", authMethod, nil, w)
if err != nil {
return nil, err
}
return wm, nil
}

// Update is used to update an existing ACL auth-method.
func (a *ACLAuthMethods) Update(authMethod *ACLAuthMethod, w *WriteOptions) (*WriteMeta, error) {
if authMethod.Name == "" {
return nil, errMissingACLAuthMethodName
}
wm, err := a.client.write("/v1/acl/auth-method/"+authMethod.Name, authMethod, nil, w)
if err != nil {
return nil, err
}
return wm, nil
}

// Delete is used to delete an ACL auth-method.
func (a *ACLAuthMethods) Delete(authMethodName string, w *WriteOptions) (*WriteMeta, error) {
if authMethodName == "" {
return nil, errMissingACLAuthMethodName
}
wm, err := a.client.delete("/v1/acl/auth-method/"+authMethodName, nil, nil, w)
if err != nil {
return nil, err
}
return wm, nil
}

// Get is used to look up an ACL auth-method.
func (a *ACLAuthMethods) Get(authMethodName string, q *QueryOptions) (*ACLAuthMethod, *QueryMeta, error) {
if authMethodName == "" {
return nil, nil, errMissingACLAuthMethodName
}
var resp ACLAuthMethod
qm, err := a.client.query("/v1/acl/auth-method/"+authMethodName, &resp, q)
if err != nil {
return nil, nil, err
}
return &resp, qm, nil
}

// ACLPolicyListStub is used to for listing ACL policies
type ACLPolicyListStub struct {
Name string
Expand Down Expand Up @@ -475,3 +549,77 @@ type ACLRoleListStub struct {
CreateIndex uint64
ModifyIndex uint64
}

// ACLAuthMethod is used to capture the properties of an authentication method
// used for single sing-on.
type ACLAuthMethod struct {

// Name is the identifier for this auth-method and is a required parameter.
Name string

// Type is the SSO identifier this auth-method is. Nomad currently only
// supports "oidc" and the API contains ACLAuthMethodTypeOIDC for
// convenience.
Type string

// Defines whether the auth-method creates a local or global token when
// performing SSO login. This should be set to either "local" or "global"
// and the API contains ACLAuthMethodTokenLocalityLocal and
// ACLAuthMethodTokenLocalityGlobal for convenience.
TokenLocality string

// MaxTokenTTL is the maximum life of a token created by this method.
MaxTokenTTL time.Duration

// Default identifies whether this is the default auth-method to use when
// attempting to login without specifying an auth-method name to use.
Default bool

// Config contains the detailed configuration which is specific to the
// auth-method.
Config *ACLAuthMethodConfig

CreateTime time.Time
ModifyTime time.Time
CreateIndex uint64
ModifyIndex uint64
}

// ACLAuthMethodConfig is used to store configuration of an auth method.
type ACLAuthMethodConfig struct {
OIDCDiscoveryURL string
OIDCClientID string
OIDCClientSecret string
BoundAudiences []string
AllowedRedirectURIs []string
DiscoveryCaPem []string
SigningAlgs []string
ClaimMappings map[string]string
ListClaimMappings map[string]string
}

// ACLAuthMethodListStub is the stub object returned when performing a listing
// of ACL auth-methods. It is intentionally minimal due to the unauthenticated
// nature of the list endpoint.
type ACLAuthMethodListStub struct {
Name string
Default bool

CreateIndex uint64
ModifyIndex uint64
}

const (
// ACLAuthMethodTokenLocalityLocal is the ACLAuthMethod.TokenLocality that
// will generate ACL tokens which can only be used on the local cluster the
// request was made.
ACLAuthMethodTokenLocalityLocal = "local"

// ACLAuthMethodTokenLocalityGlobal is the ACLAuthMethod.TokenLocality that
// will generate ACL tokens which can be used on all federated clusters.
ACLAuthMethodTokenLocalityGlobal = "global"

// ACLAuthMethodTypeOIDC the ACLAuthMethod.Type and represents an
// auth-method which uses the OIDC protocol.
ACLAuthMethodTypeOIDC = "OIDC"
)
68 changes: 68 additions & 0 deletions api/acl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"time"

"github.com/hashicorp/nomad/api/internal/testutil"
"github.com/shoenig/test/must"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -586,3 +587,70 @@ func TestACLRoles(t *testing.T) {
require.Empty(t, aclRoleListResp)
assertQueryMeta(t, queryMeta)
}

func TestACLAuthMethods(t *testing.T) {
testutil.Parallel(t)

testClient, testServer, _ := makeACLClient(t, nil, nil)
defer testServer.Stop()

// An initial listing shouldn't return any results.
aclAuthMethodsListResp, queryMeta, err := testClient.ACLAuthMethods().List(nil)
must.NoError(t, err)
must.Len(t, 0, aclAuthMethodsListResp)
assertQueryMeta(t, queryMeta)

// Create an ACL auth-method.
authMethod := ACLAuthMethod{
Name: "acl-auth-method-api-test",
Type: ACLAuthMethodTypeOIDC,
TokenLocality: ACLAuthMethodTokenLocalityLocal,
MaxTokenTTL: 15 * time.Minute,
Default: true,
}
writeMeta, err := testClient.ACLAuthMethods().Create(&authMethod, nil)
must.NoError(t, err)
assertWriteMeta(t, writeMeta)

// Another listing should return one result.
aclAuthMethodsListResp, queryMeta, err = testClient.ACLAuthMethods().List(nil)
must.NoError(t, err)
must.Len(t, 1, aclAuthMethodsListResp)
must.Eq(t, authMethod.Name, aclAuthMethodsListResp[0].Name)
must.True(t, aclAuthMethodsListResp[0].Default)
assertQueryMeta(t, queryMeta)

// Read the auth-method.
aclAuthMethodReadResp, queryMeta, err := testClient.ACLAuthMethods().Get(authMethod.Name, nil)
must.NoError(t, err)
assertQueryMeta(t, queryMeta)
must.NotNil(t, aclAuthMethodReadResp)
must.Eq(t, authMethod.Name, aclAuthMethodReadResp.Name)
must.Eq(t, authMethod.TokenLocality, aclAuthMethodReadResp.TokenLocality)
must.Eq(t, authMethod.Type, aclAuthMethodReadResp.Type)

// Update the auth-method token locality.
authMethod.TokenLocality = ACLAuthMethodTokenLocalityGlobal
writeMeta, err = testClient.ACLAuthMethods().Update(&authMethod, nil)
must.NoError(t, err)
assertWriteMeta(t, writeMeta)

// Re-read the auth-method and check the locality.
aclAuthMethodReadResp, queryMeta, err = testClient.ACLAuthMethods().Get(authMethod.Name, nil)
must.NoError(t, err)
assertQueryMeta(t, queryMeta)
must.NotNil(t, aclAuthMethodReadResp)
must.Eq(t, authMethod.Name, aclAuthMethodReadResp.Name)
must.Eq(t, authMethod.TokenLocality, aclAuthMethodReadResp.TokenLocality)

// Delete the role.
writeMeta, err = testClient.ACLAuthMethods().Delete(authMethod.Name, nil)
must.NoError(t, err)
assertWriteMeta(t, writeMeta)

// Make sure there are no ACL auth-methods now present.
aclAuthMethodsListResp, queryMeta, err = testClient.ACLAuthMethods().List(nil)
must.NoError(t, err)
must.Len(t, 0, aclAuthMethodsListResp)
assertQueryMeta(t, queryMeta)
}
Loading

0 comments on commit 84b79aa

Please sign in to comment.