All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.helidon.security.providers.oidc.DefaultTenantIdProvider Maven / Gradle / Ivy

There is a newer version: 4.1.6
Show newest version
/*
 * Copyright (c) 2023 Oracle and/or its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.helidon.security.providers.oidc;

import java.util.List;
import java.util.Optional;

import io.helidon.common.Weight;
import io.helidon.common.config.Config;
import io.helidon.security.ProviderRequest;
import io.helidon.security.providers.oidc.common.spi.TenantIdFinder;
import io.helidon.security.providers.oidc.common.spi.TenantIdProvider;
import io.helidon.security.util.TokenHandler;

import static io.helidon.security.providers.oidc.common.spi.TenantConfigFinder.DEFAULT_TENANT_ID;

/**
 * This is the default tenant id provider.
 */
@Weight(1)
class DefaultTenantIdProvider implements TenantIdProvider {

    static final String DEFAULT_TENANT_ID_STYLE = "host-header";
    static final Optional DEFAULT_TENANT_ID_VALUE = Optional.of(DEFAULT_TENANT_ID);

    @Override
    public TenantIdFinder createTenantIdFinder(Config config) {
        boolean multiTenant = config.get("multi-tenant").asBoolean().orElse(false);

        if (multiTenant) {
            String mtIdLookup = config.get("tenant-id-style").asString().orElse(DEFAULT_TENANT_ID_STYLE);
            switch (mtIdLookup) {
            case DEFAULT_TENANT_ID_STYLE:
                return new HostHeaderTenantId();
            case "token-handler":
                return new TokenHandlerTenantId(TokenHandler.create(config.get("tenant-id-handler")));
            case "domain":
                return new DomainTenantId(config.get("tenant-id-domain-level").asInt().orElse(3));
            case "none":
                return new NoTenantId();
            default:
                throw new IllegalArgumentException("Invalid configuration of multi tenancy id style. Type "
                                                           + mtIdLookup + " is not supported");
            }
        } else {
            return new NoTenantId();
        }
    }

    private static class NoTenantId implements TenantIdFinder {
        @Override
        public Optional tenantId(ProviderRequest providerRequest) {
            return DEFAULT_TENANT_ID_VALUE;
        }
    }

    private static class HostHeaderTenantId implements TenantIdFinder {
        @Override
        public Optional tenantId(ProviderRequest providerRequest) {
            List hostList = providerRequest.env().headers().get("host");
            if (hostList == null || hostList.isEmpty()) {
                return Optional.empty();
            }
            String host = hostList.get(0);
            int index = host.indexOf(':');
            if (index == -1) {
                return Optional.of(host);
            }
            return Optional.of(host.substring(0, index));
        }
    }

    private static class TokenHandlerTenantId implements TenantIdFinder {
        private final TokenHandler tokenHandler;

        TokenHandlerTenantId(TokenHandler tokenHandler) {
            this.tokenHandler = tokenHandler;
        }

        @Override
        public Optional tenantId(ProviderRequest providerRequest) {
            return tokenHandler.extractToken(providerRequest.env().headers());
        }
    }

    private static class DomainTenantId implements TenantIdFinder {
        private final HostHeaderTenantId host = new HostHeaderTenantId();
        private final int level;

        private DomainTenantId(int level) {
            this.level = level;
        }

        @Override
        public Optional tenantId(ProviderRequest providerRequest) {
            return host.tenantId(providerRequest)
                    .flatMap(host -> {
                        // this should be host name including domain, otherwise we cannot identify
                        String[] split = host.split("\\.");
                        /*
                          tenant.oracle.com
                          level 1 is .com, level 2 is oracle
                          split[0] = tenant
                          split[1] = oracle
                          split[2] = com
                          requested level: 3 (expecting tenant)
                          split.length - level = 3 - 3 = 0
                          requested level: 1 (expecting com)
                          split.length - level = 3 - 1 = 2
                         */

                        int index = split.length - level;
                        if (index >= 0 && index < split.length) {
                            return Optional.of(split[index]);
                        }
                        return Optional.empty();
                    });
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy