Skip to content

Commit 1cdde52

Browse files
authored
Merge pull request #7 from jjaferson/master
adds methods to enable creation of authentication flow via api
2 parents da7bd65 + 079b204 commit 1cdde52

4 files changed

Lines changed: 406 additions & 0 deletions

File tree

pkg/common/client.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,65 @@ func (c *Client) ListAvailableUserRealmRoles(realmName, userID string) ([]*v1alp
669669
return objects.([]*v1alpha1.KeycloakUserRole), err
670670
}
671671

672+
func (c *Client) CreateAuthenticationFlow(authFlow AuthenticationFlow, realmName string) (string, error) {
673+
path := fmt.Sprintf("realms/%s/authentication/flows", realmName)
674+
return c.create(authFlow, path, "AuthenticationFlow")
675+
}
676+
677+
func (c *Client) ListAuthenticationFlows(realmName string) ([]*AuthenticationFlow, error) {
678+
result, err := c.list(fmt.Sprintf("realms/%s/authentication/flows", realmName), "AuthenticationFlow", func(body []byte) (T, error) {
679+
var authenticationFlows []*AuthenticationFlow
680+
err := json.Unmarshal(body, &authenticationFlows)
681+
return authenticationFlows, err
682+
})
683+
if err != nil {
684+
return nil, err
685+
}
686+
return result.([]*AuthenticationFlow), err
687+
}
688+
689+
func (c *Client) FindAuthenticationFlowByAlias(flowAlias string, realmName string) (*AuthenticationFlow, error) {
690+
authFlows, err := c.ListAuthenticationFlows(realmName)
691+
if err != nil {
692+
return nil, err
693+
}
694+
for _, authFlow := range authFlows {
695+
if authFlow.Alias == flowAlias {
696+
return authFlow, nil
697+
}
698+
}
699+
700+
return nil, nil
701+
}
702+
703+
func (c *Client) AddExecutionToAuthenticatonFlow(flowAlias string, realmName string, providerID string, requirement Requirement) error {
704+
path := fmt.Sprintf("realms/%s/authentication/flows/%s/executions/execution", realmName, flowAlias)
705+
provider := map[string]string{
706+
"provider": providerID,
707+
}
708+
_, err := c.create(provider, path, "AuthenticationExecution")
709+
if err != nil {
710+
return errors.Wrapf(err, "error creating Authentication Execution %s", providerID)
711+
}
712+
713+
// updates the execution requirement after its creation
714+
if requirement != "" {
715+
execution, err := c.FindAuthenticationExecutionForFlow(flowAlias, realmName, func(execution *v1alpha1.AuthenticationExecutionInfo) bool {
716+
return execution.ProviderID == providerID
717+
})
718+
if err != nil {
719+
return errors.Wrapf(err, "error finding Authentication Execution %s", providerID)
720+
}
721+
execution.Requirement = string(requirement)
722+
err = c.UpdateAuthenticationExecutionForFlow(flowAlias, realmName, execution)
723+
if err != nil {
724+
return errors.Wrapf(err, "error updating Authentication Execution %s", providerID)
725+
}
726+
}
727+
728+
return nil
729+
}
730+
672731
func (c *Client) ListAuthenticationExecutionsForFlow(flowAlias, realmName string) ([]*v1alpha1.AuthenticationExecutionInfo, error) {
673732
result, err := c.list(fmt.Sprintf("realms/%s/authentication/flows/%s/executions", realmName, flowAlias), "AuthenticationExecution", func(body []byte) (T, error) {
674733
var authenticationExecutions []*v1alpha1.AuthenticationExecutionInfo
@@ -1068,6 +1127,11 @@ type KeycloakInterface interface {
10681127
ListAvailableUserRealmRoles(realmName, userID string) ([]*v1alpha1.KeycloakUserRole, error)
10691128
DeleteUserRealmRole(role *v1alpha1.KeycloakUserRole, realmName, userID string) error
10701129

1130+
CreateAuthenticationFlow(authFlow AuthenticationFlow, realmName string) (string, error)
1131+
ListAuthenticationFlows(realmName string) ([]*AuthenticationFlow, error)
1132+
FindAuthenticationFlowByAlias(flowAlias, realmName string) (*AuthenticationFlow, error)
1133+
AddExecutionToAuthenticatonFlow(flowAlias, realmName string, providerID string, requirement Requirement) error
1134+
10711135
ListAuthenticationExecutionsForFlow(flowAlias, realmName string) ([]*v1alpha1.AuthenticationExecutionInfo, error)
10721136
FindAuthenticationExecutionForFlow(flowAlias, realmName string, predicate func(*v1alpha1.AuthenticationExecutionInfo) bool) (*v1alpha1.AuthenticationExecutionInfo, error)
10731137
UpdateAuthenticationExecutionForFlow(flowAlias, realmName string, execution *v1alpha1.AuthenticationExecutionInfo) error

pkg/common/client_test.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,11 @@ const (
3737
GroupGetRealmRoles = "/auth/admin/realms/%s/groups/%s/role-mappings/realm"
3838
GroupGetAvailableRealmRoles = "/auth/admin/realms/%s/groups/%s/role-mappings/realm/available"
3939
AuthenticationFlowUpdateExecution = "/auth/admin/realms/%s/authentication/flows/%s/executions"
40+
AuthenticationFlowListExecution = "/auth/admin/realms/%s/authentication/flows/%s/executions"
41+
AuthenticationFlowCreateExecution = "/auth/admin/realms/%s/authentication/flows/%s/executions/execution"
4042
TokenPath = "/auth/realms/master/protocol/openid-connect/token" // nolint
43+
AuthenticationFlowCreatePath = "/auth/admin/realms/%s/authentication/flows"
44+
AuthenticationFlowListPath = "/auth/admin/realms/%s/authentication/flows"
4145
)
4246

4347
func getDummyRealm() *v1alpha1.KeycloakRealm {
@@ -572,6 +576,113 @@ func TestClient_ListAvailableGroupRealmRoles(t *testing.T) {
572576
)
573577
}
574578

579+
func TestClient_CreateAuthenticationFlow(t *testing.T) {
580+
realm := getDummyRealm()
581+
expectedPath := fmt.Sprintf(AuthenticationFlowCreatePath, realm.Spec.Realm.Realm)
582+
583+
testClientHTTPRequest(
584+
withPathAssertion(t, 201, expectedPath),
585+
func(c *Client) {
586+
_, err := c.CreateAuthenticationFlow(AuthenticationFlow{}, realm.Spec.Realm.Realm)
587+
assert.NoError(t, err)
588+
},
589+
)
590+
}
591+
592+
func TestClient_ListAuthenticationFlows(t *testing.T) {
593+
realm := getDummyRealm()
594+
expectedPath := fmt.Sprintf(AuthenticationFlowListPath, realm.Spec.Realm.Realm)
595+
596+
testClientHTTPRequest(
597+
withPathAssertion(t, 200, expectedPath),
598+
func(c *Client) {
599+
_, err := c.ListAuthenticationFlows(
600+
realm.Spec.Realm.Realm)
601+
602+
assert.NoError(t, err)
603+
},
604+
)
605+
}
606+
607+
func TestClient_FindAuthenticationFlowByAlias(t *testing.T) {
608+
const (
609+
existingAuthenticationFlowAlias string = "authdelay"
610+
existingAuthenticationFlowID string = "12345"
611+
)
612+
realm := getDummyRealm()
613+
expectedPath := fmt.Sprintf(AuthenticationFlowListPath, realm.Spec.Realm.Realm)
614+
615+
handle := withPathAssertionBody(
616+
t,
617+
200,
618+
expectedPath,
619+
[]*AuthenticationFlow{&AuthenticationFlow{
620+
Alias: existingAuthenticationFlowAlias,
621+
ID: existingAuthenticationFlowID,
622+
}},
623+
)
624+
625+
request := func(c *Client) {
626+
// when the group exists
627+
foundAuthenticationFlow, err := c.FindAuthenticationFlowByAlias(existingAuthenticationFlowAlias, realm.Spec.Realm.Realm)
628+
// then return the group instance
629+
assert.NoError(t, err)
630+
assert.NotNil(t, foundAuthenticationFlow)
631+
assert.Equal(t, existingAuthenticationFlowID, foundAuthenticationFlow.ID)
632+
633+
// when the autnetication flow doesn't exist
634+
notFoundGroup, err := c.FindAuthenticationFlowByAlias("not-existing", "dummy")
635+
// then return `nil`
636+
assert.NoError(t, err)
637+
assert.Nil(t, notFoundGroup)
638+
}
639+
640+
testClientHTTPRequest(handle, request)
641+
642+
}
643+
644+
func TestClient_AddExecutionToAuthenticatonFlow(t *testing.T) {
645+
const (
646+
authenticationFlowAlias string = "authdelay"
647+
providerID string = "delay-authentication"
648+
existingAuthenticationFlowID string = "12345"
649+
)
650+
realm := getDummyRealm()
651+
expectedPath := fmt.Sprintf(AuthenticationFlowCreateExecution, realm.Spec.Realm.Realm, authenticationFlowAlias)
652+
653+
handle := withMethodSelection(t, map[string]http.HandlerFunc{
654+
http.MethodPut: withPathAssertion(t, 200, fmt.Sprintf(AuthenticationFlowUpdateExecution, realm.Spec.Realm.Realm, authenticationFlowAlias)),
655+
http.MethodPost: withPathAssertion(t, 201, expectedPath),
656+
http.MethodGet: withPathAssertionBody(
657+
t,
658+
200,
659+
fmt.Sprintf(AuthenticationFlowListExecution, realm.Spec.Realm.Realm, authenticationFlowAlias),
660+
[]*v1alpha1.AuthenticationExecutionInfo{
661+
&v1alpha1.AuthenticationExecutionInfo{
662+
Alias: authenticationFlowAlias,
663+
ID: existingAuthenticationFlowID,
664+
ProviderID: providerID,
665+
},
666+
},
667+
),
668+
})
669+
request := func(c *Client) {
670+
err := c.AddExecutionToAuthenticatonFlow(authenticationFlowAlias,
671+
realm.Spec.Realm.Realm, providerID, Required)
672+
673+
assert.NoError(t, err)
674+
675+
// // requirement empty
676+
// err = c.AddExecutionToAuthenticatonFlow(authenticationFlowAlias,
677+
// realm.Spec.Realm.Realm, providerID, "")
678+
// assert.NoError(t, err)
679+
680+
}
681+
682+
testClientHTTPRequest(handle, request)
683+
684+
}
685+
575686
// Utility function to create a test server, register a given handler and perform
576687
// a client function to be tested
577688
func testClientHTTPRequest(

0 commit comments

Comments
 (0)