Skip to content
This repository has been archived by the owner on Nov 16, 2022. It is now read-only.

KEYCLOAK-14774 Add AuthenticationFlows and AuthenticatorConfig to KeycloakRealm CRD #230

Merged
merged 1 commit into from
Sep 9, 2020

Conversation

chlunde
Copy link
Contributor

@chlunde chlunde commented Jul 15, 2020

KEYCLOAK-14774

Additional Information

Why: Allow custom authentication flows

Verification Steps

  1. Create a Realm with custom authentication flows
  2. Verify in the admin UI that they have been imported
spec:
  instanceSelector:
    matchLabels:
      app: sso
  realm:
    displayName: Realm
    enabled: true
    id: oidc
    realm: oidc
    authenticatorConfig:
      - alias: "oidc"
        config:
          defaultProvider: "oidc"
    authenticationFlows:
    - alias: "Auto Link"
      providerId: "basic-flow"
      topLevel: true
      builtIn: false
      authenticationExecutions:
      - authenticator: "idp-create-user-if-unique"
        requirement: "ALTERNATIVE"
        priority: 0
        userSetupAllowed: false
        autheticatorFlow: false
      - authenticator: "idp-auto-link"
        requirement: "ALTERNATIVE"
        priority: 1
        userSetupAllowed: false
        autheticatorFlow: false
    - alias: "browser"
      providerId: "basic-flow"
      topLevel: true
      builtIn: false
      authenticationExecutions:
      - authenticator: "identity-provider-redirector"
        authenticatorConfig: oidc
        requirement: "ALTERNATIVE"
        priority: 0
        userSetupAllowed: false
        autheticatorFlow: false
    - alias: "registration"
      providerId: "basic-flow"
      topLevel: true
      builtIn: false
      authenticationExecutions: []
    - alias: "direct grant"
      providerId: "basic-flow"
      topLevel: true
      builtIn: false
      authenticationExecutions: []

Checklist:

Additional Notes

Two server-side issues have been created:

@chlunde
Copy link
Contributor Author

chlunde commented Jul 15, 2020

@slaskawi I created this PR for initial review/some questions. I can create an e2e test similar to keycloakRealmWithIdentityProviderTest or extend it. Which do you prefer?

As far as I can see no unit tests work at this level currently. If you have an idea for a unit test, please shout out.

@chlunde
Copy link
Contributor Author

chlunde commented Jul 17, 2020

@slaskawi should the defaults in the Java code be updated? Perhaps in https://github.com/keycloak/keycloak/blob/master/core/src/main/java/org/keycloak/representations/idm/AuthenticationFlowRepresentation.java#L27-L35

Should any boolean default to true?

@chlunde chlunde changed the title KEYCLOAK-14774 Add AuthenticationFlows and AuthenticatorConfig to KeycloakRealm CRD (WIP) KEYCLOAK-14774 Add AuthenticationFlows and AuthenticatorConfig to KeycloakRealm CRD Jul 17, 2020
@coveralls
Copy link

Coverage Status

Coverage increased (+0.09%) to 43.964% when pulling 1961102 on chlunde:authenticationflows into 709bdb7 on keycloak:master.

@slaskawi
Copy link
Contributor

@chlunde Thanks for the Pull Request! That's a very nice piece of work!

I created this PR for initial review/some questions. I can create an e2e test similar to keycloakRealmWithIdentityProviderTest or extend it. Which do you prefer?

I believe you already implemented a test (keycloakRealmWithAuthenticatorFlowTest). To me, that's good enough. @mhajas Would you like to add anything?

As far as I can see no unit tests work at this level currently. If you have an idea for a unit test, please shout out.

There's no much sense in testing those CRs at unit level. They need to be executed against a running Keycloak instance with a realm API endpoints. Testing the out on e2e level is the only way to do it.

should the defaults in the Java code be updated? Perhaps in https://github.com/keycloak/keycloak/blob/master/core/src/main/java/org/keycloak/representations/idm/AuthenticationFlowRepresentation.java#L27-L35

I think it does make sense. @stianst @mposolda WDYT?

Should any boolean default to true?

Probably not.

slaskawi
slaskawi previously approved these changes Jul 20, 2020
Copy link
Contributor

@slaskawi slaskawi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, let's wait for the other folks to answer some comments I mentioned the above.

@slaskawi slaskawi requested review from mhajas and miquelsi July 22, 2020 07:14
@chlunde
Copy link
Contributor Author

chlunde commented Aug 3, 2020

should the defaults in the Java code be updated? Perhaps in https://github.com/keycloak/keycloak/blob/master/core/src/main/java/org/keycloak/representations/idm/AuthenticationFlowRepresentation.java#L27-L35

I think it does make sense. @stianst @mposolda WDYT?

Should any boolean default to true?

Probably not.

@slaskawi I think maybe topLevel should default to true to allow for minimal CRs?

@chlunde
Copy link
Contributor Author

chlunde commented Aug 3, 2020

Re. e2e testing @slaskawi

Problem

The tests in this PR currently would not break if the "Auto Link" is missing from the import, it just checks that the IDP is there. This means we only test that the import works but if for example unknown fields are ignored on import, we will not catch errors using this e2e test.

Suggested solution

I wonder if the best e2e test is to export the realm and write jsonpath queries (or similar) to verify the contents, instead of scraping the UI and exercising the logic in keycloak.

Is it be sufficient that the e2e tests that keycloak is configured, not how keycloak behaves? Otherwise the e2e tests will have the same complexity as the keycloak e2e tests and need a real LDAP server, another OIDC provider etc. This increases runtime, complexity and increases the likelyhook of flaky tests.

Problems with export test

The downside is that the current keycloak export foarmat does not always match the REST API JSON. For example, some types are exported as components/subcomponents. So I guess the export format is subject to change and the tests could break on upgrade.

Suggested implementation

  • Add a method Export which returns a []byte JSON config.
  • Either add that to the keycloak client interface or do a type assertion in the e2e test to export the config.
  • Add helper functions in e2e/utils to validate that expressions

@chlunde
Copy link
Contributor Author

chlunde commented Aug 4, 2020

Should priority be optional? If it is, I think the Java side should be updated to calculate a priority to preserve the order in the CRD. Currently everything gets the same priority, so I assume this means unpredictable behavior.

@chlunde
Copy link
Contributor Author

chlunde commented Aug 4, 2020

If we create some additional types for deserializing the JSON, the tests could look like this:

	backup, err := exportRealm(framework, keycloakCR, realmName)
	if err != nil {
		return err
	}

	var found = false
	for _, flow := range backup.AuthenticationFlows {
		if flow.Alias == autoLinkFlow.Alias {
			found = true
			if diff := cmp.Diff(autoLinkFlow, flow, cmpopts.IgnoreFields(flow, "ID")); diff != "" {
				return fmt.Errorf("AuthenticatorFlow mismatch (-want +got):\n%s", diff)
			}
		}
	}

	if !found {
		return fmt.Errorf("Imported flow %v missing", autoLinkFlow.Alias)
	}

	if diff := cmp.Diff(keycloakRealmCR.Spec.Realm.AuthenticatorConfig, backup.AuthenticatorConfig, cmpopts.IgnoreFields(backup.AuthenticatorConfig, "ID")); diff != "" {
		return fmt.Errorf("AuthenticatorConfig mismatch (-want +got):\n%s", diff)
	}

	return nil

using jsonpath was not a good idea because it is not type safe, the code is similar length or longer, and it is not easier to update at all.

@chlunde
Copy link
Contributor Author

chlunde commented Aug 4, 2020

@mhajas @miquelsi Do you know when will you be able to look at this? I have a few other changes I would like which depends on the direction we take here, so I'm blocked from finishing this now.

Do you think this style of test is OK? #230 (comment)

Copy link
Contributor

@slaskawi slaskawi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chlunde I like your approach for testing but this Pull Request touches too many things at once. Our maintenance process is a bit heavyweight and we need to avoid multi-purpose Pull Requests.

So here's my proposal:

  • Could you please create another JIRA with a goal to refactor our Realm/Client/User end to end tests to the new partial backup approach? I think it goes without saying that comparing with a partial export is far better than just throwing a payload at Keycloak and checking if it returned HTTP 200 OK. But I'd like to make it consistent across our test codebase.
  • Could you please remove the new partial-test approach from this Pull Request and leave only bits related to adding AuthenticationFlow and AuthenticationConfig?
  • Could you please squash your changes into two commits - feature implementation (that's the first commit) and vendor directory changes (that's the second one)?
  • Could you please rebase your changes?

Please let me know once it's ready to be reviewed. And good work - especially for the partial backup. It's very clever!

@slaskawi
Copy link
Contributor

@chlunde Could you please let me know if/when do you plan to introduce changes I mentioned in my review comment?

@chlunde
Copy link
Contributor Author

chlunde commented Aug 28, 2020

@slaskawi Sorry, I had more time when you had vacation, and now when you are back I have less time for this 🙁 I created https://issues.redhat.com/browse/KEYCLOAK-15378 - I'll try to create a PR for that soon.

So basically you want this PR to be without any e2e testing for now. Would you also like to

  • A: have all the other PRs without e2e testing, and then later get another PR per feature with e2e tests
  • B: leave the other PRs until the e2e testing "framework" is merged, and then I'll rebase them before you review/merge them?

@slaskawi
Copy link
Contributor

slaskawi commented Sep 1, 2020

@slaskawi Sorry, I had more time when you had vacation, and now when you are back I have less time for this slightly_frowning_face I created https://issues.redhat.com/browse/KEYCLOAK-15378 - I'll try to create a PR for that soon.

@chlunde No worries! This is what usually happens in summer :)

So basically you want this PR to be without any e2e testing for now. Would you also like to

A: have all the other PRs without e2e testing, and then later get another PR per feature with e2e tests
B: leave the other PRs until the e2e testing "framework" is merged, and then I'll rebase them before you review/merge them?

@chlunde I definitely prefer solution A. Adding those fields to the CRs is by far more important than the new testing framework.

@chlunde
Copy link
Contributor Author

chlunde commented Sep 4, 2020

@slaskawi ready for review now.

@slaskawi slaskawi merged commit 7bfac7a into keycloak:master Sep 9, 2020
@slaskawi
Copy link
Contributor

slaskawi commented Sep 9, 2020

@chlunde Great stuff! Thanks for the contribution!

@sathieu
Copy link
Contributor

sathieu commented Apr 19, 2021

Hello @slaskawi @chlunde I still have NPE with this config:

apiVersion: keycloak.org/v1alpha1
kind: KeycloakRealm
metadata:
  name: sso
  namespace: keycloak
spec:
  realm:
    id: basic
    realm: basic
    enabled: true
    displayName: Qualif
    identityProviders:
    - alias: agents-example-interne
      providerId: oidc
      displayName: Agents Example interne
      enabled: true
      # updateProfileFirstLoginMode: on
      # trustEmail: false
      # storeToken: false
      # addReadTokenRoleOnCreate: false
      # authenticateByDefault: false
      #linkOnly: false
      # firstBrokerLoginFlowAlias: first broker login
      config:
        clientId: k8s-qt-auth
        tokenUrl: https://auth.example.org/auth/realms/agents-example-interne/protocol/openid-connect/token
        authorizationUrl: https://auth.example.org/auth/realms/agents-example-interne/protocol/openid-connect/auth
        clientAuthMethod: client_secret_post
        logoutUrl: https://auth.example.org/auth/realms/agents-example-interne/protocol/openid-connect/logout
        syncMode: IMPORT
        clientSecret: T0ken
        # useJwksUrl: "true"
    authenticationFlows:
    - alias: browser
      providerId: "basic-flow"
      description: browser based authentication
      authenticationExecutions:
        - authenticator: identity-provider-redirector
          requirement: ALTERNATIVE
          priority: 25
          userSetupAllowed: false
          autheticatorFlow: false
  instanceSelector:
    matchLabels:
      app: sso
07:51:54,735 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (default task-1) Uncaught server error: java.lang.NullPointerException
        at org.keycloak.keycloak-server-spi-private@12.0.3//org.keycloak.models.utils.RepresentationToModel.importAuthenticationFlows(RepresentationToModel.java:728)
        at org.keycloak.keycloak-server-spi-private@12.0.3//org.keycloak.models.utils.RepresentationToModel.importRealm(RepresentationToModel.java:288)
        at org.keycloak.keycloak-services@12.0.3//org.keycloak.services.managers.RealmManager.importRealm(RealmManager.java:558)
        at org.keycloak.keycloak-services@12.0.3//org.keycloak.services.managers.RealmManager.importRealm(RealmManager.java:501)
        at org.keycloak.keycloak-services@12.0.3//org.keycloak.services.resources.admin.RealmsAdminResource.importRealm(RealmsAdminResource.java:131)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[...]

@sathieu
Copy link
Contributor

sathieu commented Apr 19, 2021

Adding

    authenticatorConfig:
      - alias: "oidc"
        config:
          defaultProvider: "oidc"

Changes the NPE to :

08:00:05,878 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (default task-1) Uncaught server error: java.lang.NullPointerException
        at org.keycloak.keycloak-model-jpa@12.0.3//org.keycloak.models.jpa.RealmAdapter.setRegistrationFlow(RealmAdapter.java:1506)
        at org.keycloak.keycloak-server-spi-private@12.0.3//org.keycloak.models.utils.RepresentationToModel.importAuthenticationFlows(RepresentationToModel.java:760)
        at org.keycloak.keycloak-server-spi-private@12.0.3//org.keycloak.models.utils.RepresentationToModel.importRealm(RepresentationToModel.java:288)
        at org.keycloak.keycloak-services@12.0.3//org.keycloak.services.managers.RealmManager.importRealm(RealmManager.java:558)
        at org.keycloak.keycloak-services@12.0.3//org.keycloak.services.managers.RealmManager.importRealm(RealmManager.java:501)
        at org.keycloak.keycloak-services@12.0.3//org.keycloak.services.resources.admin.RealmsAdminResource.importRealm(RealmsAdminResource.java:131)

@chlunde chlunde deleted the authenticationflows branch April 20, 2021 16:01
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants