1
18 package io.undertow.security.impl;
19
20 import io.undertow.security.api.AuthenticationMechanism;
21 import io.undertow.security.api.AuthenticationMechanismFactory;
22 import io.undertow.security.api.SecurityContext;
23 import io.undertow.security.idm.Account;
24 import io.undertow.security.idm.Credential;
25 import io.undertow.security.idm.IdentityManager;
26 import io.undertow.security.idm.X509CertificateCredential;
27 import io.undertow.server.HttpServerExchange;
28 import io.undertow.server.RenegotiationRequiredException;
29 import io.undertow.server.SSLSessionInfo;
30 import io.undertow.server.handlers.form.FormParserFactory;
31
32 import org.xnio.SslClientAuthMode;
33
34 import javax.net.ssl.SSLPeerUnverifiedException;
35
36 import java.io.IOException;
37 import java.security.cert.Certificate;
38 import java.security.cert.X509Certificate;
39 import java.util.Map;
40
41
49 public class ClientCertAuthenticationMechanism implements AuthenticationMechanism {
50
51 public static final AuthenticationMechanismFactory FACTORY = new Factory();
52
53 public static final String FORCE_RENEGOTIATION = "force_renegotiation";
54
55 private final String name;
56 private final IdentityManager identityManager;
57
58
61 private final boolean forceRenegotiation;
62
63 public ClientCertAuthenticationMechanism() {
64 this(true);
65 }
66
67 public ClientCertAuthenticationMechanism(boolean forceRenegotiation) {
68 this("CLIENT_CERT", forceRenegotiation);
69 }
70
71 public ClientCertAuthenticationMechanism(final String mechanismName) {
72 this(mechanismName, true);
73 }
74
75 public ClientCertAuthenticationMechanism(final String mechanismName, boolean forceRenegotiation) {
76 this(mechanismName, forceRenegotiation, null);
77 }
78
79 public ClientCertAuthenticationMechanism(final String mechanismName, boolean forceRenegotiation, IdentityManager identityManager) {
80 this.name = mechanismName;
81 this.forceRenegotiation = forceRenegotiation;
82 this.identityManager = identityManager;
83 }
84
85 @SuppressWarnings("deprecation")
86 private IdentityManager getIdentityManager(SecurityContext securityContext) {
87 return identityManager != null ? identityManager : securityContext.getIdentityManager();
88 }
89
90 public AuthenticationMechanismOutcome authenticate(final HttpServerExchange exchange, final SecurityContext securityContext) {
91 SSLSessionInfo sslSession = exchange.getConnection().getSslSessionInfo();
92 if (sslSession != null) {
93 try {
94 Certificate[] clientCerts = getPeerCertificates(exchange, sslSession, securityContext);
95 if (clientCerts[0] instanceof X509Certificate) {
96 Credential credential = new X509CertificateCredential((X509Certificate) clientCerts[0]);
97
98 IdentityManager idm = getIdentityManager(securityContext);
99 Account account = idm.verify(credential);
100 if (account != null) {
101 securityContext.authenticationComplete(account, name, false);
102 return AuthenticationMechanismOutcome.AUTHENTICATED;
103 }
104 }
105 } catch (SSLPeerUnverifiedException e) {
106
107
108 }
109 }
110
111
116
117 return AuthenticationMechanismOutcome.NOT_ATTEMPTED;
118 }
119
120 private Certificate[] getPeerCertificates(final HttpServerExchange exchange, SSLSessionInfo sslSession, SecurityContext securityContext) throws SSLPeerUnverifiedException {
121 try {
122 return sslSession.getPeerCertificates();
123 } catch (RenegotiationRequiredException e) {
124
125 if (forceRenegotiation && securityContext.isAuthenticationRequired()) {
126 try {
127 sslSession.renegotiate(exchange, SslClientAuthMode.REQUESTED);
128 return sslSession.getPeerCertificates();
129
130 } catch (IOException e1) {
131
132 } catch (RenegotiationRequiredException e1) {
133
134 }
135 }
136 }
137 throw new SSLPeerUnverifiedException("");
138 }
139
140 @Override
141 public ChallengeResult sendChallenge(HttpServerExchange exchange, SecurityContext securityContext) {
142 return ChallengeResult.NOT_SENT;
143 }
144
145 public static final class Factory implements AuthenticationMechanismFactory {
146
147 @Deprecated
148 public Factory(IdentityManager identityManager) {}
149
150 public Factory() {}
151
152 @Override
153 public AuthenticationMechanism create(String mechanismName,IdentityManager identityManager, FormParserFactory formParserFactory, Map<String, String> properties) {
154 String forceRenegotiation = properties.get(FORCE_RENEGOTIATION);
155 return new ClientCertAuthenticationMechanism(mechanismName, forceRenegotiation == null ? true : "true".equals(forceRenegotiation), identityManager);
156 }
157 }
158
159 }
160