public SamlServiceProvider build() {

        // Must ensure that OpenSAML is initialized before building a SAML service provider.
        SamlInitializer.ensureAvailability();

        if (entityId == null) {
            throw new IllegalStateException("entity ID is not specified");
        }
        if (credentialResolver == null) {
            throw new IllegalStateException(CredentialResolver.class.getSimpleName() + " is not specified");
        }
        if (authorizer == null) {
            throw new IllegalStateException(Authorizer.class.getSimpleName() + " is not specified");
        }

        final Credential signingCredential = credentialResolver.apply(signingKey);
        if (signingCredential == null) {
            throw new IllegalStateException("cannot resolve a " + Credential.class.getSimpleName() +
                                            " for signing: " + signingKey);
        }
        final Credential encryptionCredential = credentialResolver.apply(encryptionKey);
        if (encryptionCredential == null) {
            throw new IllegalStateException("cannot resolve a " + Credential.class.getSimpleName() +
                                            " for encryption: " + encryptionKey);
        }
        validateSignatureAlgorithm(signatureAlgorithm, signingCredential);
        validateSignatureAlgorithm(signatureAlgorithm, encryptionCredential);

        // Initialize single logout service configurations.
        final List<SamlEndpoint> sloEndpoints;
        if (this.sloEndpoints.isEmpty()) {
            // Add two endpoints by default if there's no SLO endpoint specified by a user.
            sloEndpoints = ImmutableList.of(ofHttpPost("/saml/slo/post"),
                                            ofHttpRedirect("/saml/slo/redirect"));
        } else {
            sloEndpoints = ImmutableList.copyOf(this.sloEndpoints);
        }

        // Initialize assertion consumer service configurations.
        final List<SamlAssertionConsumerConfig> assertionConsumerConfigs;
        if (acsConfigBuilders.isEmpty()) {
            // Add two endpoints by default if there's no ACS endpoint specified by a user.
            assertionConsumerConfigs =
                    ImmutableList.of(new SamlAssertionConsumerConfigBuilder(this, ofHttpPost("/saml/acs/post"))
                                             .asDefault().build(),
                                     new SamlAssertionConsumerConfigBuilder(
                                             this, ofHttpRedirect("/saml/acs/redirect")).build());
        } else {
            // Make the first ACS endpoint as default since there's no way to specify a default ACS endpoint
            // at the moment.
            acsConfigBuilders.get(0).asDefault();

            assertionConsumerConfigs = acsConfigBuilders.stream()
                                                        .map(SamlAssertionConsumerConfigBuilder::build)
                                                        .collect(toImmutableList());
        }

        // Collect assertion consumer service endpoints for checking duplication and existence.
        final Set<SamlEndpoint> acsEndpoints =
                assertionConsumerConfigs.stream().map(SamlAssertionConsumerConfig::endpoint)
                                        .collect(toImmutableSet());
        if (acsEndpoints.size() != assertionConsumerConfigs.size()) {
            throw new IllegalStateException("duplicated access consumer services exist");
        }

        // Initialize identity provider configurations.
        if (idpConfigBuilders.isEmpty()) {
            throw new IllegalStateException("no identity provider configuration is specified");
        }
        // If there is only one IdP, it will be automatically a default IdP.
        if (idpConfigBuilders.size() == 1) {
            idpConfigBuilders.get(0).asDefault();
        }

        final ImmutableMap.Builder<String, SamlIdentityProviderConfig> idpConfigs = ImmutableMap.builder();
        SamlIdentityProviderConfig defaultIdpConfig = null;
        for (final SamlIdentityProviderConfigBuilder builder : idpConfigBuilders) {
            if (builder.acsEndpoint() != null && !acsEndpoints.contains(builder.acsEndpoint())) {
                throw new IllegalStateException("unspecified access consumer service at " +
                                                builder.acsEndpoint());
            }

            final SamlIdentityProviderConfig config = builder.build(credentialResolver);

            validateSignatureAlgorithm(signatureAlgorithm, config.signingCredential());
            validateSignatureAlgorithm(signatureAlgorithm, config.encryptionCredential());

            idpConfigs.put(config.entityId(), config);

            if (builder.isDefault()) {
                if (defaultIdpConfig != null) {
                    throw new IllegalStateException("there has to be only one default identity provider");
                }
                defaultIdpConfig = config;
            }
        }

        if (idpConfigSelector == null) {
            if (defaultIdpConfig == null) {
                throw new IllegalStateException("default identity provider does not exist");
            }

            // Configure a default identity provider selector which always returns a default identity provider.
            final SamlIdentityProviderConfig defaultConfig = defaultIdpConfig;
            idpConfigSelector =
                    (unused1, unused2, unused3) -> UnmodifiableFuture.completedFuture(defaultConfig);
        }

        // entityID would be used as a secret by default.
        try {
            requestIdManager = firstNonNull(requestIdManager,
                                            SamlRequestIdManager.ofJwt(entityId, entityId, 60, 5));
        } catch (UnsupportedEncodingException e) {
            throw new IllegalStateException("cannot create a " + SamlRequestIdManager.class.getSimpleName(),
                                            e);
        }

        return new SamlServiceProvider(authorizer,
                                       entityId,
                                       hostname,
                                       signingCredential,
                                       encryptionCredential,
                                       signatureAlgorithm,
                                       hostConfigBuilder.toAutoFiller(),
                                       metadataPath,
                                       idpConfigs.build(),
                                       defaultIdpConfig,
                                       idpConfigSelector,
                                       assertionConsumerConfigs,
                                       sloEndpoints,
                                       requestIdManager,
                                       ssoHandler,
                                       sloHandler,
                                       signatureRequired);
    }
Builds a {@link SamlServiceProvider} which helps a {@link Server} have a SAML-based
authentication.
saml/src/main/java/com/linecorp/armeria/server/saml/SamlServiceProviderBuilder.java