Skip to content

Commit 0dd07dd

Browse files
committed
Added sample of client-cert using JCE
1 parent 1d23c9c commit 0dd07dd

File tree

9 files changed

+651
-0
lines changed

9 files changed

+651
-0
lines changed

servlet/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
<module>security-digest</module>
3434
<module>security-form-based</module>
3535
<module>security-clientcert</module>
36+
<module>security-clientcert-jce</module>
3637

3738

3839
<module>security-programmatic</module>
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<parent>
7+
<groupId>org.javaee7</groupId>
8+
<artifactId>servlet</artifactId>
9+
<version>1.0-SNAPSHOT</version>
10+
</parent>
11+
12+
<artifactId>servlet-security-clientcert-jce</artifactId>
13+
<packaging>war</packaging>
14+
15+
<name>Java EE 7 Sample: servlet - security-clientcert-jce</name>
16+
17+
<dependencies>
18+
<dependency>
19+
<groupId>org.bouncycastle</groupId>
20+
<artifactId>bcprov-jdk15on</artifactId>
21+
<version>1.59</version>
22+
</dependency>
23+
24+
<dependency>
25+
<groupId>org.bouncycastle</groupId>
26+
<artifactId>bcpkix-jdk15on</artifactId>
27+
<version>1.59</version>
28+
</dependency>
29+
</dependencies>
30+
31+
<build>
32+
<plugins>
33+
<plugin>
34+
<groupId>org.apache.maven.plugins</groupId>
35+
<artifactId>maven-surefire-plugin</artifactId>
36+
<configuration>
37+
<skipTests>${skipServletClientCertificate}</skipTests>
38+
<systemPropertyVariables>
39+
<buildDirectory>${project.build.directory}</buildDirectory>
40+
</systemPropertyVariables>
41+
</configuration>
42+
</plugin>
43+
</plugins>
44+
</build>
45+
46+
</project>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/** Copyright Payara Services Limited **/
2+
package org.javaee7.servlet.security.clientcert.jce;
3+
4+
import java.io.IOException;
5+
import java.security.Security;
6+
7+
import javax.servlet.ServletException;
8+
import javax.servlet.annotation.WebServlet;
9+
import javax.servlet.http.HttpServlet;
10+
import javax.servlet.http.HttpServletRequest;
11+
import javax.servlet.http.HttpServletResponse;
12+
13+
import org.bouncycastle.jce.provider.BouncyCastleProvider;
14+
15+
/**
16+
* This Servlet is used to set our custom JCE provider.
17+
*
18+
* @author Arjan Tijms
19+
*/
20+
@WebServlet(urlPatterns = { "/BouncyServlet" })
21+
public class BouncyServlet extends HttpServlet {
22+
23+
private static final long serialVersionUID = 1L;
24+
25+
@Override
26+
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
27+
28+
BouncyCastleProvider provider = new BouncyCastleProvider();
29+
provider.put("CertificateFactory.X.509", MyJCECertificateFactory.class.getName());
30+
31+
// Installs the JCE provider
32+
int pos = Security.insertProviderAt(provider, 1);
33+
34+
// Returns the position of the JCE provider, this should be 1.
35+
response.getWriter().print("pos:" + pos);
36+
}
37+
38+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/** Copyright Payara Services Limited **/
2+
package org.javaee7.servlet.security.clientcert.jce;
3+
4+
import java.io.InputStream;
5+
import java.security.cert.Certificate;
6+
import java.security.cert.CertificateException;
7+
import java.security.cert.X509Certificate;
8+
9+
import org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory;
10+
11+
/**
12+
* Our own custom CertificateFactory based on the bouncy castle one.
13+
*
14+
* <p>
15+
* We use this to provide a customized certificate, based on the certificate
16+
* instance created by bouncy castle.
17+
*
18+
* @author Arjan Tijms
19+
*/
20+
public class MyJCECertificateFactory extends CertificateFactory {
21+
22+
@Override
23+
public Certificate engineGenerateCertificate(InputStream in) throws CertificateException {
24+
Certificate certificate = super.engineGenerateCertificate(in);
25+
26+
if (certificate instanceof X509Certificate == false) {
27+
return certificate;
28+
}
29+
30+
return new MyJCEX509Certificate((X509Certificate) certificate);
31+
}
32+
33+
}
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
/** Copyright Payara Services Limited **/
2+
package org.javaee7.servlet.security.clientcert.jce;
3+
4+
import java.math.BigInteger;
5+
import java.security.InvalidKeyException;
6+
import java.security.NoSuchAlgorithmException;
7+
import java.security.NoSuchProviderException;
8+
import java.security.Principal;
9+
import java.security.PublicKey;
10+
import java.security.SignatureException;
11+
import java.security.cert.CertificateEncodingException;
12+
import java.security.cert.CertificateException;
13+
import java.security.cert.CertificateExpiredException;
14+
import java.security.cert.CertificateNotYetValidException;
15+
import java.security.cert.X509Certificate;
16+
import java.util.Date;
17+
import java.util.Set;
18+
19+
import javax.security.auth.x500.X500Principal;
20+
21+
/**
22+
* @author Arjan Tijms
23+
*/
24+
public class MyJCEX509Certificate extends X509Certificate {
25+
26+
private final X509Certificate certificate;
27+
28+
public MyJCEX509Certificate(X509Certificate certificate) {
29+
this.certificate = certificate;
30+
}
31+
32+
@Override
33+
public X500Principal getSubjectX500Principal() {
34+
35+
X500Principal principal = certificate.getSubjectX500Principal();
36+
37+
if ("C=UK,ST=lak,L=zak,O=kaz,OU=bar,CN=lfoo".equals(principal.getName())) {
38+
return new X500Principal("CN=u1");
39+
}
40+
41+
return principal;
42+
}
43+
44+
@Override
45+
public Principal getSubjectDN() {
46+
47+
Principal principal = certificate.getSubjectDN();
48+
49+
if ("CN=lfoo,OU=bar,O=kaz,L=zak,ST=lak,C=UK".equals(principal.getName())) {
50+
// Doesn't have to be X500 but keep it for simplicity
51+
return new X500Principal("CN=u1");
52+
}
53+
54+
return principal;
55+
}
56+
57+
@Override
58+
public boolean hasUnsupportedCriticalExtension() {
59+
return certificate.hasUnsupportedCriticalExtension();
60+
}
61+
62+
@Override
63+
public Set<String> getCriticalExtensionOIDs() {
64+
return certificate.getCriticalExtensionOIDs();
65+
}
66+
67+
@Override
68+
public Set<String> getNonCriticalExtensionOIDs() {
69+
return certificate.getCriticalExtensionOIDs();
70+
}
71+
72+
@Override
73+
public byte[] getExtensionValue(String oid) {
74+
return certificate.getExtensionValue(oid);
75+
}
76+
77+
@Override
78+
public void checkValidity() throws CertificateExpiredException, CertificateNotYetValidException {
79+
certificate.checkValidity();
80+
81+
}
82+
83+
@Override
84+
public void checkValidity(Date date) throws CertificateExpiredException, CertificateNotYetValidException {
85+
certificate.checkValidity(date);
86+
}
87+
88+
@Override
89+
public int getVersion() {
90+
return certificate.getVersion();
91+
}
92+
93+
@Override
94+
public BigInteger getSerialNumber() {
95+
return certificate.getSerialNumber();
96+
}
97+
98+
@Override
99+
public Principal getIssuerDN() {
100+
return certificate.getIssuerDN();
101+
}
102+
103+
@Override
104+
public Date getNotBefore() {
105+
return certificate.getNotBefore();
106+
}
107+
108+
@Override
109+
public Date getNotAfter() {
110+
return certificate.getNotAfter();
111+
}
112+
113+
@Override
114+
public byte[] getTBSCertificate() throws CertificateEncodingException {
115+
return certificate.getTBSCertificate();
116+
}
117+
118+
@Override
119+
public byte[] getSignature() {
120+
return certificate.getSignature();
121+
}
122+
123+
@Override
124+
public String getSigAlgName() {
125+
return certificate.getSigAlgName();
126+
}
127+
128+
@Override
129+
public String getSigAlgOID() {
130+
return certificate.getSigAlgOID();
131+
}
132+
133+
@Override
134+
public byte[] getSigAlgParams() {
135+
return certificate.getSigAlgParams();
136+
}
137+
138+
@Override
139+
public boolean[] getIssuerUniqueID() {
140+
return certificate.getIssuerUniqueID();
141+
}
142+
143+
@Override
144+
public boolean[] getSubjectUniqueID() {
145+
return certificate.getSubjectUniqueID();
146+
}
147+
148+
@Override
149+
public boolean[] getKeyUsage() {
150+
return certificate.getKeyUsage();
151+
}
152+
153+
@Override
154+
public int getBasicConstraints() {
155+
return certificate.getBasicConstraints();
156+
}
157+
158+
@Override
159+
public byte[] getEncoded() throws CertificateEncodingException {
160+
return certificate.getEncoded();
161+
}
162+
163+
@Override
164+
public void verify(PublicKey key) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException {
165+
certificate.verify(key);
166+
167+
}
168+
169+
@Override
170+
public void verify(PublicKey key, String sigProvider) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException {
171+
certificate.verify(key, sigProvider);
172+
173+
}
174+
175+
@Override
176+
public String toString() {
177+
return certificate.toString();
178+
}
179+
180+
@Override
181+
public PublicKey getPublicKey() {
182+
return certificate.getPublicKey();
183+
}
184+
185+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/** Copyright Payara Services Limited **/
2+
package org.javaee7.servlet.security.clientcert.jce;
3+
4+
import java.io.IOException;
5+
import java.security.Security;
6+
7+
import javax.servlet.ServletException;
8+
import javax.servlet.annotation.WebServlet;
9+
import javax.servlet.http.HttpServlet;
10+
import javax.servlet.http.HttpServletRequest;
11+
import javax.servlet.http.HttpServletResponse;
12+
13+
import org.bouncycastle.jce.provider.BouncyCastleProvider;
14+
15+
/**
16+
* @author Arjan Tijms
17+
*/
18+
@WebServlet(urlPatterns = { "/SecureServlet" })
19+
public class SecureServlet extends HttpServlet {
20+
21+
private static final long serialVersionUID = 1L;
22+
23+
@Override
24+
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
25+
26+
response.getWriter().print("principal " + request.getUserPrincipal() + " in role g1:" + request.isUserInRole("g1"));
27+
}
28+
29+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
/** Copyright Payara Services Limited **/
4+
-->
5+
<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
6+
<glassfish-web-app>
7+
8+
<security-role-mapping>
9+
<role-name>g1</role-name>
10+
<group-name>g1</group-name>
11+
<principal-name>CN=u1</principal-name>
12+
</security-role-mapping>
13+
14+
</glassfish-web-app>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
/** Copyright Payara Services Limited **/
4+
-->
5+
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
6+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
7+
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
8+
version="3.1">
9+
10+
<security-constraint>
11+
<web-resource-collection>
12+
<web-resource-name>SecureServlet</web-resource-name>
13+
<url-pattern>/SecureServlet</url-pattern>
14+
<http-method>GET</http-method>
15+
<http-method>POST</http-method>
16+
</web-resource-collection>
17+
<auth-constraint>
18+
<role-name>g1</role-name>
19+
</auth-constraint>
20+
</security-constraint>
21+
22+
<login-config>
23+
<auth-method>CLIENT-CERT</auth-method>
24+
</login-config>
25+
26+
<security-role>
27+
<role-name>g1</role-name>
28+
</security-role>
29+
</web-app>

0 commit comments

Comments
 (0)