Merge branch 'jetty-9.3.x' into jetty-9.4.x
This commit is contained in:
commit
167f6c8d23
|
@ -20,7 +20,7 @@ node {
|
|||
{
|
||||
stage 'Compile'
|
||||
withEnv(mvnEnv) {
|
||||
timeout(15) {
|
||||
timeout(time: 15, unit: 'MINUTES') {
|
||||
sh "mvn -B clean install -Dtest=None"
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ node {
|
|||
{
|
||||
stage 'Javadoc'
|
||||
withEnv(mvnEnv) {
|
||||
timeout(15) {
|
||||
timeout(time: 15, unit: 'MINUTES') {
|
||||
sh "mvn -B javadoc:javadoc"
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ node {
|
|||
{
|
||||
stage 'Test'
|
||||
withEnv(mvnEnv) {
|
||||
timeout(60) {
|
||||
timeout(time: 60, unit: 'MINUTES') {
|
||||
// Run test phase / ignore test failures
|
||||
sh "mvn -B install -Dmaven.test.failure.ignore=true"
|
||||
// Report failures in the jenkins UI
|
||||
|
@ -54,6 +54,7 @@ node {
|
|||
testResults: '**/target/surefire-reports/TEST-*.xml'])
|
||||
// Collect up the jacoco execution results
|
||||
step([$class: 'JacocoPublisher',
|
||||
inclusionPattern: "**/org/eclipse/jetty/**/*.class",
|
||||
execPattern: '**/target/jacoco.exec',
|
||||
classPattern: '**/target/classes',
|
||||
sourcePattern: '**/src/main/java'])
|
||||
|
|
|
@ -396,18 +396,30 @@ jetty.sslContext.keyStorePassword::
|
|||
|
||||
To enable two-way authentication, you first need to activate the ssl module as shown in the previous section.
|
||||
|
||||
First you need load the `ssl` module and `https` module.
|
||||
[source%nowrap,ini,linenums]
|
||||
.start.d/ssl.ini
|
||||
.$JETTY_BASE/start.d/ssl.ini
|
||||
----
|
||||
# Module: ssl
|
||||
--module=ssl
|
||||
jetty.secure.port=8443
|
||||
jetty.keystore=etc/keystore
|
||||
jetty.keystore.password=OBF:
|
||||
jetty.keymanager.password=OBF:
|
||||
jetty.truststore=etc/truststore
|
||||
jetty.truststore.password=OBF:
|
||||
|
||||
jetty.ssl.host=0.0.0.0
|
||||
jetty.ssl.port=8583
|
||||
jetty.sslContext.keyStorePath=etc/keystore
|
||||
jetty.sslContext.trustStorePath=etc/keystore
|
||||
jetty.sslContext.keyStorePassword=OBF:
|
||||
jetty.sslContext.keyManagerPassword=OBF:
|
||||
jetty.sslContext.trustStorePassword=OBF:
|
||||
jetty.sslContext.trustStoreType=JKS
|
||||
# enable two way authentication
|
||||
jetty.ssl.needClientAuth=true
|
||||
jetty.sslContext.needClientAuth=true
|
||||
----
|
||||
|
||||
[source%nowrap,ini,linenums]
|
||||
.$JETTY_BASE/start.d/https.ini
|
||||
----
|
||||
# Module: https
|
||||
--module=https
|
||||
----
|
||||
|
||||
[[layout-of-keystore-and-truststore]]
|
||||
|
@ -415,19 +427,47 @@ jetty.ssl.needClientAuth=true
|
|||
|
||||
`keystore` only contains the server's private key and certificate.
|
||||
|
||||
[[img-certificate-chain]]
|
||||
image::images/certificate-chain.png[title="Certificate chain", alt="Certificate chain"]
|
||||
|
||||
[literal]
|
||||
.The structure of KeyStore file
|
||||
....
|
||||
├── PrivateKeyEntry
|
||||
│ ├── PrivateKey
|
||||
│ ├── Certificate chain
|
||||
│ │ ├── Server certificate (end entity)
|
||||
│ │ ├── Intermediary CA certificate
|
||||
│ │ └── Root CA certificate
|
||||
├── TrustedCertEntry
|
||||
│ └── Intermediary CA certificate
|
||||
└── TrustedCertEntry
|
||||
└── Root CA certificate
|
||||
....
|
||||
|
||||
[TIP]
|
||||
====
|
||||
└── PrivateKeyEntry +
|
||||
└── Certificate chain +
|
||||
├── Intermediary CA certificate +
|
||||
└── Root CA certificate +
|
||||
are optional
|
||||
====
|
||||
|
||||
[source%nowrap,plain,linenums]
|
||||
----
|
||||
$ keytool -list -keystore keystore -storetype jks -storepass '' -v
|
||||
$ cd $JETTY_BASE
|
||||
$ keytool -list -keystore etc/keystore -storetype jks -storepass '' -v
|
||||
|
||||
Keystore type: JKS
|
||||
Keystore provider: SUN
|
||||
|
||||
Your keystore contains 1 entry
|
||||
Your keystore contains 3 entries
|
||||
|
||||
Alias name: *.example.com
|
||||
Creation date: Sep 12, 2016
|
||||
Creation date: Sep 20, 2016
|
||||
Entry type: PrivateKeyEntry
|
||||
Certificate chain length: 1
|
||||
Certificate chain length: 3
|
||||
Certificate[1]:
|
||||
Owner: CN=*.example.com, OU=Web Servers, O="Example.com Co.,Ltd.", C=CN
|
||||
Issuer: CN="Example.com Co.,Ltd. ETP CA", OU=CA Center, O="Example.com Co.,Ltd.", C=CN
|
||||
|
@ -477,26 +517,98 @@ KeyIdentifier [
|
|||
]
|
||||
]
|
||||
|
||||
Certificate[2]:
|
||||
Owner: CN="Example.com Co.,Ltd. ETP CA", OU=CA Center, O="Example.com Co.,Ltd.", C=CN
|
||||
Issuer: CN="Example.com Co.,Ltd. Root CA", OU=CA Center, O="Example.com Co.,Ltd.", C=CN
|
||||
Serial number: f6e7b86f6fdb467f9498fb599310198f
|
||||
Valid from: Wed Nov 18 00:00:00 CST 2015 until: Sun Nov 18 00:00:00 CST 2035
|
||||
Certificate fingerprints:
|
||||
MD5: ED:A3:91:57:D8:B8:6E:B1:01:58:55:5C:33:14:F5:99
|
||||
SHA1: D9:A4:93:9D:A6:F8:A3:F9:FD:85:51:E2:C5:2E:0B:EE:80:E7:D0:22
|
||||
SHA256: BF:54:7A:F6:CA:0C:FA:EF:93:B6:6B:6E:2E:D7:44:A8:40:00:EC:69:3A:2C:CC:9A:F7:FE:8E:6F:C0:FA:22:38
|
||||
Signature algorithm name: SHA256withRSA
|
||||
Version: 3
|
||||
|
||||
Extensions:
|
||||
|
||||
#1: ObjectId: 2.5.29.35 Criticality=false
|
||||
AuthorityKeyIdentifier [
|
||||
KeyIdentifier [
|
||||
0000: A6 BD 5F B3 E8 7D 74 3D 20 44 66 1A 16 3B 1B DF .._...t= Df..;..
|
||||
0010: E6 E6 04 46 ...F
|
||||
]
|
||||
]
|
||||
|
||||
#2: ObjectId: 2.5.29.19 Criticality=true
|
||||
BasicConstraints:[
|
||||
CA:true
|
||||
PathLen:2147483647
|
||||
]
|
||||
|
||||
#3: ObjectId: 2.5.29.15 Criticality=true
|
||||
KeyUsage [
|
||||
Key_CertSign
|
||||
Crl_Sign
|
||||
]
|
||||
|
||||
#4: ObjectId: 2.5.29.14 Criticality=false
|
||||
SubjectKeyIdentifier [
|
||||
KeyIdentifier [
|
||||
0000: 44 9B AD 31 E7 FE CA D5 5A 8E 17 55 F9 F0 1D 6B D..1....Z..U...k
|
||||
0010: F5 A5 8F C1 ....
|
||||
]
|
||||
]
|
||||
|
||||
Certificate[3]:
|
||||
Owner: CN="Example.com Co.,Ltd. Root CA", OU=CA Center, O="Example.com Co.,Ltd.", C=CN
|
||||
Issuer: CN="Example.com Co.,Ltd. Root CA", OU=CA Center, O="Example.com Co.,Ltd.", C=CN
|
||||
Serial number: f0a45bc9972c458cbeae3f723055f1ac
|
||||
Valid from: Wed Nov 18 00:00:00 CST 2015 until: Sun Nov 18 00:00:00 CST 2114
|
||||
Certificate fingerprints:
|
||||
MD5: 50:61:62:22:71:60:F7:69:2E:27:42:6B:62:31:82:79
|
||||
SHA1: 7A:6D:A6:48:B1:43:03:3B:EA:A0:29:2F:19:65:9C:9B:0E:B1:03:1A
|
||||
SHA256: 05:3B:9C:5B:8E:18:61:61:D1:9C:AA:0E:8C:B1:EA:44:C2:6E:67:5D:96:30:EC:8C:F6:6F:E1:EC:AD:00:60:F1
|
||||
Signature algorithm name: SHA256withRSA
|
||||
Version: 3
|
||||
|
||||
Extensions:
|
||||
|
||||
#1: ObjectId: 2.5.29.35 Criticality=false
|
||||
AuthorityKeyIdentifier [
|
||||
KeyIdentifier [
|
||||
0000: A6 BD 5F B3 E8 7D 74 3D 20 44 66 1A 16 3B 1B DF .._...t= Df..;..
|
||||
0010: E6 E6 04 46 ...F
|
||||
]
|
||||
]
|
||||
|
||||
#2: ObjectId: 2.5.29.19 Criticality=true
|
||||
BasicConstraints:[
|
||||
CA:true
|
||||
PathLen:2147483647
|
||||
]
|
||||
|
||||
#3: ObjectId: 2.5.29.15 Criticality=true
|
||||
KeyUsage [
|
||||
Key_CertSign
|
||||
Crl_Sign
|
||||
]
|
||||
|
||||
#4: ObjectId: 2.5.29.14 Criticality=false
|
||||
SubjectKeyIdentifier [
|
||||
KeyIdentifier [
|
||||
0000: A6 BD 5F B3 E8 7D 74 3D 20 44 66 1A 16 3B 1B DF .._...t= Df..;..
|
||||
0010: E6 E6 04 46 ...F
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
|
||||
*******************************************
|
||||
*******************************************
|
||||
|
||||
----
|
||||
|
||||
`truststore` contains intermediary CA and root CA.
|
||||
|
||||
[source%nowrap,plain,linenums]
|
||||
----
|
||||
$ keytool -list -keystore truststore -storetype jks -storepass '' -v
|
||||
|
||||
Keystore type: JKS
|
||||
Keystore provider: SUN
|
||||
|
||||
Your keystore contains 2 entries
|
||||
|
||||
Alias name: example.com co.,ltd. etp ca
|
||||
Creation date: Sep 12, 2016
|
||||
Creation date: Sep 20, 2016
|
||||
Entry type: trustedCertEntry
|
||||
|
||||
Owner: CN="Example.com Co.,Ltd. ETP CA", OU=CA Center, O="Example.com Co.,Ltd.", C=CN
|
||||
|
@ -547,7 +659,7 @@ KeyIdentifier [
|
|||
|
||||
|
||||
Alias name: example.com co.,ltd. root ca
|
||||
Creation date: Sep 12, 2016
|
||||
Creation date: Sep 20, 2016
|
||||
Entry type: trustedCertEntry
|
||||
|
||||
Owner: CN="Example.com Co.,Ltd. Root CA", OU=CA Center, O="Example.com Co.,Ltd.", C=CN
|
||||
|
@ -597,10 +709,27 @@ KeyIdentifier [
|
|||
*******************************************
|
||||
----
|
||||
|
||||
____
|
||||
[NOTE]
|
||||
If you use a keystore which contains only one `PrivateKeyEntry` item as the `keystore` and the `truststore`, you may get a `javax.net.ssl.SSLHandshakeException` with `null cert chain` message.
|
||||
____
|
||||
In addition, you can split `$JETTY/etc/keystore` as two files.
|
||||
One is `$JETTY/etc/keystore` which only contains the server’s private key and certificate,
|
||||
the other is `$JETTY/etc/truststore` which contains intermediary CA and root CA.
|
||||
|
||||
[literal]
|
||||
.The structure of `$JETTY/etc/keystore`
|
||||
....
|
||||
└── PrivateKeyEntry
|
||||
├── PrivateKey
|
||||
└── Certificate chain
|
||||
└── Server certificate (end entity)
|
||||
....
|
||||
|
||||
[literal]
|
||||
.The structure of `$JETTY/etc/truststore`
|
||||
....
|
||||
├── TrustedCertEntry
|
||||
│ └── Intermediary CA certificate
|
||||
└── TrustedCertEntry
|
||||
└── Root CA certificate
|
||||
....
|
||||
|
||||
[[configuring-sslcontextfactory]]
|
||||
==== Configuring the Jetty SslContextFactory
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 5.9 KiB |
|
@ -181,20 +181,22 @@ public class LdapLoginModule extends AbstractLoginModule
|
|||
|
||||
public class LDAPUserInfo extends UserInfo
|
||||
{
|
||||
|
||||
Attributes attributes;
|
||||
|
||||
/**
|
||||
* @param userName
|
||||
* @param credential
|
||||
*/
|
||||
public LDAPUserInfo(String userName, Credential credential)
|
||||
public LDAPUserInfo(String userName, Credential credential, Attributes attributes)
|
||||
{
|
||||
super(userName, credential);
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> doFetchRoles() throws Exception
|
||||
{
|
||||
return getUserRoles(_rootContext, getUserName());
|
||||
return getUserRoles(_rootContext, getUserName(), attributes);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -214,7 +216,8 @@ public class LdapLoginModule extends AbstractLoginModule
|
|||
*/
|
||||
public UserInfo getUserInfo(String username) throws Exception
|
||||
{
|
||||
String pwdCredential = getUserCredentials(username);
|
||||
Attributes attributes = getUserAttributes(username);
|
||||
String pwdCredential = getUserCredentials(attributes);
|
||||
|
||||
if (pwdCredential == null)
|
||||
{
|
||||
|
@ -223,7 +226,7 @@ public class LdapLoginModule extends AbstractLoginModule
|
|||
|
||||
pwdCredential = convertCredentialLdapToJetty(pwdCredential);
|
||||
Credential credential = Credential.getCredential(pwdCredential);
|
||||
return new LDAPUserInfo(username, credential);
|
||||
return new LDAPUserInfo(username, credential, attributes);
|
||||
}
|
||||
|
||||
protected String doRFC2254Encoding(String inputString)
|
||||
|
@ -258,7 +261,7 @@ public class LdapLoginModule extends AbstractLoginModule
|
|||
}
|
||||
|
||||
/**
|
||||
* attempts to get the users credentials from the users context
|
||||
* attempts to get the users LDAP attributes from the users context
|
||||
* <p>
|
||||
* NOTE: this is not an user authenticated operation
|
||||
*
|
||||
|
@ -266,53 +269,39 @@ public class LdapLoginModule extends AbstractLoginModule
|
|||
* @return
|
||||
* @throws LoginException
|
||||
*/
|
||||
private String getUserCredentials(String username) throws LoginException
|
||||
private Attributes getUserAttributes(String username) throws LoginException
|
||||
{
|
||||
String ldapCredential = null;
|
||||
Attributes attributes = null;
|
||||
|
||||
SearchControls ctls = new SearchControls();
|
||||
ctls.setCountLimit(1);
|
||||
ctls.setDerefLinkFlag(true);
|
||||
ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
|
||||
|
||||
String filter = "(&(objectClass={0})({1}={2}))";
|
||||
|
||||
LOG.debug("Searching for users with filter: \'" + filter + "\'" + " from base dn: " + _userBaseDn);
|
||||
|
||||
try
|
||||
{
|
||||
Object[] filterArguments = {_userObjectClass, _userIdAttribute, username};
|
||||
NamingEnumeration<SearchResult> results = _rootContext.search(_userBaseDn, filter, filterArguments, ctls);
|
||||
|
||||
LOG.debug("Found user?: " + results.hasMoreElements());
|
||||
|
||||
if (!results.hasMoreElements())
|
||||
{
|
||||
throw new LoginException("User not found.");
|
||||
}
|
||||
|
||||
SearchResult result = findUser(username);
|
||||
|
||||
Attributes attributes = result.getAttributes();
|
||||
|
||||
Attribute attribute = attributes.get(_userPasswordAttribute);
|
||||
if (attribute != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] value = (byte[]) attribute.get();
|
||||
|
||||
ldapCredential = new String(value);
|
||||
}
|
||||
catch (NamingException e)
|
||||
{
|
||||
LOG.debug("no password available under attribute: " + _userPasswordAttribute);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (NamingException e)
|
||||
{
|
||||
SearchResult result;
|
||||
try {
|
||||
result = findUser(username);
|
||||
attributes = result.getAttributes();
|
||||
}
|
||||
catch (NamingException e) {
|
||||
throw new LoginException("Root context binding failure.");
|
||||
}
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
private String getUserCredentials(Attributes attributes) throws LoginException
|
||||
{
|
||||
String ldapCredential = null;
|
||||
|
||||
Attribute attribute = attributes.get(_userPasswordAttribute);
|
||||
if (attribute != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] value = (byte[]) attribute.get();
|
||||
|
||||
ldapCredential = new String(value);
|
||||
}
|
||||
catch (NamingException e)
|
||||
{
|
||||
LOG.debug("no password available under attribute: " + _userPasswordAttribute);
|
||||
}
|
||||
}
|
||||
|
||||
LOG.debug("user cred is: " + ldapCredential);
|
||||
|
@ -330,9 +319,22 @@ public class LdapLoginModule extends AbstractLoginModule
|
|||
* @return
|
||||
* @throws LoginException
|
||||
*/
|
||||
private List<String> getUserRoles(DirContext dirContext, String username) throws LoginException, NamingException
|
||||
private List<String> getUserRoles(DirContext dirContext, String username, Attributes attributes) throws LoginException, NamingException
|
||||
{
|
||||
String userDn = _userRdnAttribute + "=" + username + "," + _userBaseDn;
|
||||
String rdnValue = username;
|
||||
Attribute attribute = attributes.get(_userRdnAttribute);
|
||||
if (attribute != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
rdnValue = (String) attribute.get(); // switch to the value stored in the _userRdnAttribute if we can
|
||||
}
|
||||
catch (NamingException e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
String userDn = _userRdnAttribute + "=" + rdnValue + "," + _userBaseDn;
|
||||
|
||||
return getUserRolesByDn(dirContext, userDn);
|
||||
}
|
||||
|
@ -537,7 +539,7 @@ public class LdapLoginModule extends AbstractLoginModule
|
|||
String filter = "(&(objectClass={0})({1}={2}))";
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Searching for users with filter: \'" + filter + "\'" + " from base dn: " + _userBaseDn);
|
||||
LOG.debug("Searching for user " + username + " with filter: \'" + filter + "\'" + " from base dn: " + _userBaseDn);
|
||||
|
||||
Object[] filterArguments = new Object[]{
|
||||
_userObjectClass,
|
||||
|
|
Loading…
Reference in New Issue