Skip to content

Commit

Permalink
Merge pull request #7 from jjaferson/master
Browse files Browse the repository at this point in the history
adds methods to enable creation of authentication flow via api
  • Loading branch information
davidffrench authored May 5, 2020
2 parents da7bd65 + 079b204 commit 1cdde52
Show file tree
Hide file tree
Showing 4 changed files with 406 additions and 0 deletions.
64 changes: 64 additions & 0 deletions pkg/common/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,65 @@ func (c *Client) ListAvailableUserRealmRoles(realmName, userID string) ([]*v1alp
return objects.([]*v1alpha1.KeycloakUserRole), err
}

func (c *Client) CreateAuthenticationFlow(authFlow AuthenticationFlow, realmName string) (string, error) {
path := fmt.Sprintf("realms/%s/authentication/flows", realmName)
return c.create(authFlow, path, "AuthenticationFlow")
}

func (c *Client) ListAuthenticationFlows(realmName string) ([]*AuthenticationFlow, error) {
result, err := c.list(fmt.Sprintf("realms/%s/authentication/flows", realmName), "AuthenticationFlow", func(body []byte) (T, error) {
var authenticationFlows []*AuthenticationFlow
err := json.Unmarshal(body, &authenticationFlows)
return authenticationFlows, err
})
if err != nil {
return nil, err
}
return result.([]*AuthenticationFlow), err
}

func (c *Client) FindAuthenticationFlowByAlias(flowAlias string, realmName string) (*AuthenticationFlow, error) {
authFlows, err := c.ListAuthenticationFlows(realmName)
if err != nil {
return nil, err
}
for _, authFlow := range authFlows {
if authFlow.Alias == flowAlias {
return authFlow, nil
}
}

return nil, nil
}

func (c *Client) AddExecutionToAuthenticatonFlow(flowAlias string, realmName string, providerID string, requirement Requirement) error {
path := fmt.Sprintf("realms/%s/authentication/flows/%s/executions/execution", realmName, flowAlias)
provider := map[string]string{
"provider": providerID,
}
_, err := c.create(provider, path, "AuthenticationExecution")
if err != nil {
return errors.Wrapf(err, "error creating Authentication Execution %s", providerID)
}

// updates the execution requirement after its creation
if requirement != "" {
execution, err := c.FindAuthenticationExecutionForFlow(flowAlias, realmName, func(execution *v1alpha1.AuthenticationExecutionInfo) bool {
return execution.ProviderID == providerID
})
if err != nil {
return errors.Wrapf(err, "error finding Authentication Execution %s", providerID)
}
execution.Requirement = string(requirement)
err = c.UpdateAuthenticationExecutionForFlow(flowAlias, realmName, execution)
if err != nil {
return errors.Wrapf(err, "error updating Authentication Execution %s", providerID)
}
}

return nil
}

func (c *Client) ListAuthenticationExecutionsForFlow(flowAlias, realmName string) ([]*v1alpha1.AuthenticationExecutionInfo, error) {
result, err := c.list(fmt.Sprintf("realms/%s/authentication/flows/%s/executions", realmName, flowAlias), "AuthenticationExecution", func(body []byte) (T, error) {
var authenticationExecutions []*v1alpha1.AuthenticationExecutionInfo
Expand Down Expand Up @@ -1068,6 +1127,11 @@ type KeycloakInterface interface {
ListAvailableUserRealmRoles(realmName, userID string) ([]*v1alpha1.KeycloakUserRole, error)
DeleteUserRealmRole(role *v1alpha1.KeycloakUserRole, realmName, userID string) error

CreateAuthenticationFlow(authFlow AuthenticationFlow, realmName string) (string, error)
ListAuthenticationFlows(realmName string) ([]*AuthenticationFlow, error)
FindAuthenticationFlowByAlias(flowAlias, realmName string) (*AuthenticationFlow, error)
AddExecutionToAuthenticatonFlow(flowAlias, realmName string, providerID string, requirement Requirement) error

ListAuthenticationExecutionsForFlow(flowAlias, realmName string) ([]*v1alpha1.AuthenticationExecutionInfo, error)
FindAuthenticationExecutionForFlow(flowAlias, realmName string, predicate func(*v1alpha1.AuthenticationExecutionInfo) bool) (*v1alpha1.AuthenticationExecutionInfo, error)
UpdateAuthenticationExecutionForFlow(flowAlias, realmName string, execution *v1alpha1.AuthenticationExecutionInfo) error
Expand Down
111 changes: 111 additions & 0 deletions pkg/common/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ const (
GroupGetRealmRoles = "/auth/admin/realms/%s/groups/%s/role-mappings/realm"
GroupGetAvailableRealmRoles = "/auth/admin/realms/%s/groups/%s/role-mappings/realm/available"
AuthenticationFlowUpdateExecution = "/auth/admin/realms/%s/authentication/flows/%s/executions"
AuthenticationFlowListExecution = "/auth/admin/realms/%s/authentication/flows/%s/executions"
AuthenticationFlowCreateExecution = "/auth/admin/realms/%s/authentication/flows/%s/executions/execution"
TokenPath = "/auth/realms/master/protocol/openid-connect/token" // nolint
AuthenticationFlowCreatePath = "/auth/admin/realms/%s/authentication/flows"
AuthenticationFlowListPath = "/auth/admin/realms/%s/authentication/flows"
)

func getDummyRealm() *v1alpha1.KeycloakRealm {
Expand Down Expand Up @@ -572,6 +576,113 @@ func TestClient_ListAvailableGroupRealmRoles(t *testing.T) {
)
}

func TestClient_CreateAuthenticationFlow(t *testing.T) {
realm := getDummyRealm()
expectedPath := fmt.Sprintf(AuthenticationFlowCreatePath, realm.Spec.Realm.Realm)

testClientHTTPRequest(
withPathAssertion(t, 201, expectedPath),
func(c *Client) {
_, err := c.CreateAuthenticationFlow(AuthenticationFlow{}, realm.Spec.Realm.Realm)
assert.NoError(t, err)
},
)
}

func TestClient_ListAuthenticationFlows(t *testing.T) {
realm := getDummyRealm()
expectedPath := fmt.Sprintf(AuthenticationFlowListPath, realm.Spec.Realm.Realm)

testClientHTTPRequest(
withPathAssertion(t, 200, expectedPath),
func(c *Client) {
_, err := c.ListAuthenticationFlows(
realm.Spec.Realm.Realm)

assert.NoError(t, err)
},
)
}

func TestClient_FindAuthenticationFlowByAlias(t *testing.T) {
const (
existingAuthenticationFlowAlias string = "authdelay"
existingAuthenticationFlowID string = "12345"
)
realm := getDummyRealm()
expectedPath := fmt.Sprintf(AuthenticationFlowListPath, realm.Spec.Realm.Realm)

handle := withPathAssertionBody(
t,
200,
expectedPath,
[]*AuthenticationFlow{&AuthenticationFlow{
Alias: existingAuthenticationFlowAlias,
ID: existingAuthenticationFlowID,
}},
)

request := func(c *Client) {
// when the group exists
foundAuthenticationFlow, err := c.FindAuthenticationFlowByAlias(existingAuthenticationFlowAlias, realm.Spec.Realm.Realm)
// then return the group instance
assert.NoError(t, err)
assert.NotNil(t, foundAuthenticationFlow)
assert.Equal(t, existingAuthenticationFlowID, foundAuthenticationFlow.ID)

// when the autnetication flow doesn't exist
notFoundGroup, err := c.FindAuthenticationFlowByAlias("not-existing", "dummy")
// then return `nil`
assert.NoError(t, err)
assert.Nil(t, notFoundGroup)
}

testClientHTTPRequest(handle, request)

}

func TestClient_AddExecutionToAuthenticatonFlow(t *testing.T) {
const (
authenticationFlowAlias string = "authdelay"
providerID string = "delay-authentication"
existingAuthenticationFlowID string = "12345"
)
realm := getDummyRealm()
expectedPath := fmt.Sprintf(AuthenticationFlowCreateExecution, realm.Spec.Realm.Realm, authenticationFlowAlias)

handle := withMethodSelection(t, map[string]http.HandlerFunc{
http.MethodPut: withPathAssertion(t, 200, fmt.Sprintf(AuthenticationFlowUpdateExecution, realm.Spec.Realm.Realm, authenticationFlowAlias)),
http.MethodPost: withPathAssertion(t, 201, expectedPath),
http.MethodGet: withPathAssertionBody(
t,
200,
fmt.Sprintf(AuthenticationFlowListExecution, realm.Spec.Realm.Realm, authenticationFlowAlias),
[]*v1alpha1.AuthenticationExecutionInfo{
&v1alpha1.AuthenticationExecutionInfo{
Alias: authenticationFlowAlias,
ID: existingAuthenticationFlowID,
ProviderID: providerID,
},
},
),
})
request := func(c *Client) {
err := c.AddExecutionToAuthenticatonFlow(authenticationFlowAlias,
realm.Spec.Realm.Realm, providerID, Required)

assert.NoError(t, err)

// // requirement empty
// err = c.AddExecutionToAuthenticatonFlow(authenticationFlowAlias,
// realm.Spec.Realm.Realm, providerID, "")
// assert.NoError(t, err)

}

testClientHTTPRequest(handle, request)

}

// Utility function to create a test server, register a given handler and perform
// a client function to be tested
func testClientHTTPRequest(
Expand Down
Loading

0 comments on commit 1cdde52

Please sign in to comment.