1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.linecorp.centraldogma.server.auth.saml;
17
18 import static com.google.common.base.Preconditions.checkState;
19
20 import java.io.File;
21 import java.io.IOException;
22 import java.security.GeneralSecurityException;
23 import java.time.Duration;
24
25 import org.opensaml.security.credential.CredentialResolver;
26
27 import com.fasterxml.jackson.core.JsonProcessingException;
28
29 import com.linecorp.armeria.server.saml.KeyStoreCredentialResolverBuilder;
30 import com.linecorp.armeria.server.saml.SamlServiceProvider;
31 import com.linecorp.armeria.server.saml.SamlServiceProviderBuilder;
32 import com.linecorp.centraldogma.server.auth.AuthConfig;
33 import com.linecorp.centraldogma.server.auth.AuthProvider;
34 import com.linecorp.centraldogma.server.auth.AuthProviderFactory;
35 import com.linecorp.centraldogma.server.auth.AuthProviderParameters;
36 import com.linecorp.centraldogma.server.auth.saml.SamlAuthProperties.Acs;
37 import com.linecorp.centraldogma.server.auth.saml.SamlAuthProperties.Idp;
38 import com.linecorp.centraldogma.server.auth.saml.SamlAuthProperties.KeyStore;
39
40
41
42
43 public final class SamlAuthProviderFactory implements AuthProviderFactory {
44 @Override
45 public AuthProvider create(AuthProviderParameters parameters) {
46 final SamlAuthProperties properties = getProperties(parameters.authConfig());
47 try {
48 final KeyStore ks = properties.keyStore();
49 final Idp idp = properties.idp();
50 final SamlServiceProviderBuilder builder = SamlServiceProvider.builder();
51 builder.entityId(properties.entityId())
52 .hostname(properties.hostname())
53 .signingKey(properties.signingKey())
54 .encryptionKey(properties.encryptionKey())
55 .authorizer(parameters.authorizer())
56 .ssoHandler(new SamlAuthSsoHandler(
57 parameters.sessionIdGenerator(),
58 parameters.loginSessionPropagator(),
59 Duration.ofMillis(parameters.authConfig().sessionTimeoutMillis()),
60 parameters.authConfig().loginNameNormalizer(),
61 properties.idp().subjectLoginNameIdFormat(),
62 properties.idp().attributeLoginName()))
63 .credentialResolver(credentialResolver(ks))
64 .signatureAlgorithm(ks.signatureAlgorithm())
65 .idp()
66 .entityId(idp.entityId())
67 .ssoEndpoint(idp.endpoint())
68 .signingKey(idp.signingKey())
69 .encryptionKey(idp.encryptionKey());
70 final Acs acs = properties.acs();
71 if (acs != null && !acs.endpoints().isEmpty()) {
72 acs.endpoints().forEach(builder::acs);
73 }
74
75 return new SamlAuthProvider(builder.build());
76 } catch (Exception e) {
77 throw new IllegalStateException("Failed to create " +
78 SamlAuthProvider.class.getSimpleName(), e);
79 }
80 }
81
82 private static SamlAuthProperties getProperties(AuthConfig authConfig) {
83 try {
84 final SamlAuthProperties p = authConfig.properties(SamlAuthProperties.class);
85 checkState(p != null, "authentication properties are not specified");
86 return p;
87 } catch (JsonProcessingException e) {
88 throw new IllegalArgumentException("Failed to get properties from " +
89 AuthConfig.class.getSimpleName(), e);
90 }
91 }
92
93 private static CredentialResolver credentialResolver(KeyStore keyStore)
94 throws IOException, GeneralSecurityException {
95 final KeyStoreCredentialResolverBuilder builder;
96 final String path = keyStore.path();
97 final File file = new File(path);
98 if (file.isFile()) {
99 builder = new KeyStoreCredentialResolverBuilder(file);
100 } else {
101 builder = new KeyStoreCredentialResolverBuilder(
102 SamlAuthProviderFactory.class.getClassLoader(), path);
103 }
104
105 builder.type(keyStore.type())
106 .password(keyStore.password())
107 .keyPasswords(keyStore.keyPasswords());
108 return builder.build();
109 }
110 }