Multitenancy using Keycloak and SpringBoot

James picture James · Oct 26, 2017 · Viewed 8.2k times · Source

I am using spring boot adapter and keycloak spring boot adapter to perform multitenancy where i can access the page using an ip and domain name. But when I run gradlew script it seems this bean is not detected no changes has happened. even after i included a logger, the log is not printed so i assume that this file is not read at all. Am I missing something? or are there any implementations that I can use for multitenancy. thanks.

KeycloakTomcatContextCustomizer

@Component
public class KeycloakTomcatContextCustomizer implements TomcatContextCustomizer
{
    private static final Logger logger = LoggerFactory.getLogger(KeycloakTomcatContextCustomizerBean.class);

    @Override
    public void customize(Context context)
    {
        LoginConfig loginConfig = new LoginConfig();
        loginConfig.setAuthMethod("--KEYCLOAK--");
        context.setLoginConfig(loginConfig);
        context.addSecurityRole("myproject");

        SecurityConstraint constraint = new SecurityConstraint();
        constraint.addAuthRole("myproject");

        SecurityCollection collection = new SecurityCollection();
        collection.addPattern("/contexts");
        constraint.addCollection(collection);

        context.addConstraint(constraint);

        context.addParameter("keycloak.config.resolver", HostBasedKeycloakResolver.class.getName());
    }

    public class HostBasedKeycloakResolver extends KeycloakSpringBootConfigResolver
    {
        private KeycloakDeployment keycloakDeployment;

        @Autowired
        private AdapterConfig adapterConfig;

        @Override
        public KeycloakDeployment resolve(OIDCHttpFacade.Request request) {
        if (keycloakDeployment != null) {
            return keycloakDeployment;
        }

            //get the host part here

        //build keycloakdeployment
            keycloakDeployment = KeycloakDeploymentBuilder.build(adapterConfig);
            adapterConfig.setAuthServerUrl("https://"+host+"/auth");
            System.out.println(adapterConfig.getAuthServerUrl());
            return keycloakDeployment;
        }
    }


}

My application.yml\

keycloak:
  cors: true
  realm: Boot-Project
  realmKey: AARjANBgkqhkiYUitdhjnCAQ8AMIIBCgKCAQEArOS/TTjkgjdoiQ7F6m5x206lJ+K9VBpEjkjrignxIdH7pJDWv9UMg2CL1q3Tfkjg/YdjkljgkbsnqrSzjBcIU5HQ2AQLkRm2eCPuLIB23d2VS3hZGqvbyqN42hbk/oRhloS0tS2/frq4fIeU53KQiRPPiBt1IEO7DINoDUXdyOWS7g/rSrMkjjUm9SohXdv8u3aB+mnI8gNwEag17Cj+wqoc1smPj5jb/8Ab3MynQHv4ekgXYFPI5BEQSXXflBLbL2kjqR2xP8y8XTsOz58XLyWBydjN2R37uds9D2TqipU3tdc286b276RhNCwIDAQAB
  auth-server-url: https://${__AUTH_VM__:localhost}/auth
  ssl-required: none
  resource: myproject
  bearer-only: true
  public-client: false
  credentials:
    secret: ls5f7c3g-d045-444f-8234-6cth6970726y
  securityConstraints[0]:
    securityCollections[0]:
      name: secured context api and app
      authRoles: 
        - commongui
      patterns:
        - /contexts/*
        - /config.json

Answer

Jayson Zanarias picture Jayson Zanarias · Dec 25, 2017

I've encountered a similar case with what you are trying to achieve, your code seems okay. The following might help you:

1) Official documentation from keycloak on how to implement multi-tenancy: http://www.keycloak.org/docs/3.2/securing_apps/topics/oidc/java/multi-tenancy.html

from there, it is pointed out that you need to configure which KeycloackConfigResolver to use but unfortunately, as the time of this writing, there is no convenient way to do it in Spring Boot as I found on this ticket:

2) Custom KeycloakConfigResolver for Spring Boot adapter: https://issues.jboss.org/browse/KEYCLOAK-4139?_sscc=t

3) After #1 and #2, what could be happening is that Spring might be overriding your implementation class depending on how your Spring configuration is being resolved. Try to override a few more methods from the class you are extending, add some logging, then check Spring logs during run time if that is what's happening (you'll see something like this "...Overriding bean definition for bean...with a different definition: replacing...with... ")

4) Try excluding the concerned class so that your implementation class will not be overridden For example: @SpringBootApplication(exclude = {KeycloakSpringBootConfiguration.class})

Hope this helps or provides a few ideas.

Regards, Sir. JZ