You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by kr...@apache.org on 2018/11/07 17:09:46 UTC
knox git commit: KNOX-1549 - KnoxSSO should support signing keys per
topology
Repository: knox
Updated Branches:
refs/heads/master 44e2bfc8a -> 2135bc22c
KNOX-1549 - KnoxSSO should support signing keys per topology
Signed-off-by: Kevin Risden <kr...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/knox/repo
Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/2135bc22
Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/2135bc22
Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/2135bc22
Branch: refs/heads/master
Commit: 2135bc22c0b5beb383450d6a574bcc21078e4b19
Parents: 44e2bfc
Author: Kevin Risden <kr...@apache.org>
Authored: Thu Nov 1 16:50:21 2018 -0400
Committer: Kevin Risden <kr...@apache.org>
Committed: Wed Nov 7 11:37:14 2018 -0500
----------------------------------------------------------------------
.../federation/AbstractJWTFilterTest.java | 34 ++--
.../security/impl/DefaultKeystoreService.java | 32 ++-
.../impl/DefaultTokenAuthorityService.java | 51 +++--
.../impl/DefaultTokenAuthorityServiceTest.java | 56 ++++++
.../resources/keystores/testSigningKeyName.jks | Bin 0 -> 2238 bytes
.../gateway/service/knoxsso/WebSSOResource.java | 76 ++++---
.../service/knoxsso/WebSSOResourceTest.java | 199 ++++++++++++++-----
.../knoxtoken/TokenServiceResourceTest.java | 52 +++--
.../services/security/KeystoreService.java | 36 ++--
.../security/token/JWTokenAuthority.java | 6 +-
10 files changed, 370 insertions(+), 172 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/knox/blob/2135bc22/gateway-provider-security-jwt/src/test/java/org/apache/knox/gateway/provider/federation/AbstractJWTFilterTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-jwt/src/test/java/org/apache/knox/gateway/provider/federation/AbstractJWTFilterTest.java b/gateway-provider-security-jwt/src/test/java/org/apache/knox/gateway/provider/federation/AbstractJWTFilterTest.java
index ea8607d..387b274 100644
--- a/gateway-provider-security-jwt/src/test/java/org/apache/knox/gateway/provider/federation/AbstractJWTFilterTest.java
+++ b/gateway-provider-security-jwt/src/test/java/org/apache/knox/gateway/provider/federation/AbstractJWTFilterTest.java
@@ -31,7 +31,6 @@ import org.apache.knox.gateway.provider.federation.jwt.filter.SSOCookieFederatio
import org.apache.knox.gateway.security.PrimaryPrincipal;
import org.apache.knox.gateway.services.security.impl.X509CertificateUtil;
import org.apache.knox.gateway.services.security.token.JWTokenAuthority;
-import org.apache.knox.gateway.services.security.token.TokenServiceException;
import org.apache.knox.gateway.services.security.token.impl.JWT;
import org.easymock.EasyMock;
import org.junit.After;
@@ -48,7 +47,6 @@ import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
import java.security.AccessController;
@@ -107,7 +105,7 @@ public abstract class AbstractJWTFilterTest {
}
@After
- public void teardown() throws Exception {
+ public void teardown() {
handler.destroy();
}
@@ -675,7 +673,7 @@ public abstract class AbstractJWTFilterTest {
TestFilterChain chain = new TestFilterChain();
handler.doFilter(request, response, chain);
Assert.assertTrue("doFilterCalled should not be false.", !chain.doFilterCalled);
- Assert.assertTrue("No Subject should be returned.", chain.subject == null);
+ Assert.assertNull("No Subject should be returned.", chain.subject);
} catch (ServletException se) {
fail("Should NOT have thrown a ServletException.");
}
@@ -765,51 +763,56 @@ public abstract class AbstractJWTFilterTest {
private PublicKey verifyingKey;
- public TestJWTokenAuthority(PublicKey verifyingKey) {
+ TestJWTokenAuthority(PublicKey verifyingKey) {
this.verifyingKey = verifyingKey;
}
@Override
- public JWT issueToken(Subject subject, String algorithm) throws TokenServiceException {
+ public JWT issueToken(Subject subject, String algorithm) {
return null;
}
@Override
- public JWT issueToken(Principal p, String algorithm) throws TokenServiceException {
+ public JWT issueToken(Principal p, String algorithm) {
return null;
}
@Override
- public JWT issueToken(Principal p, String audience, String algorithm)
- throws TokenServiceException {
+ public JWT issueToken(Principal p, String audience, String algorithm) {
return null;
}
@Override
- public boolean verifyToken(JWT token) throws TokenServiceException {
+ public boolean verifyToken(JWT token) {
JWSVerifier verifier = new RSASSAVerifier((RSAPublicKey) verifyingKey);
return token.verify(verifier);
}
@Override
public JWT issueToken(Principal p, String audience, String algorithm,
- long expires) throws TokenServiceException {
+ long expires) {
return null;
}
@Override
public JWT issueToken(Principal p, List<String> audiences, String algorithm,
- long expires) throws TokenServiceException {
+ long expires) {
+ return null;
+ }
+
+ @Override
+ public JWT issueToken(Principal p, List<String> audiences, String algorithm, long expires,
+ String signingKeystoreName, String signingKeystoreAlias, char[] signingKeystorePassphrase) {
return null;
}
@Override
- public JWT issueToken(Principal p, String algorithm, long expires) throws TokenServiceException {
+ public JWT issueToken(Principal p, String algorithm, long expires) {
return null;
}
@Override
- public boolean verifyToken(JWT token, RSAPublicKey publicKey) throws TokenServiceException {
+ public boolean verifyToken(JWT token, RSAPublicKey publicKey) {
JWSVerifier verifier = new RSASSAVerifier(publicKey);
return token.verify(verifier);
}
@@ -820,8 +823,7 @@ public abstract class AbstractJWTFilterTest {
Subject subject = null;
@Override
- public void doFilter(ServletRequest request, ServletResponse response)
- throws IOException, ServletException {
+ public void doFilter(ServletRequest request, ServletResponse response) {
doFilterCalled = true;
subject = Subject.getSubject( AccessController.getContext() );
http://git-wip-us.apache.org/repos/asf/knox/blob/2135bc22/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultKeystoreService.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultKeystoreService.java b/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultKeystoreService.java
index 26ca369..08257ca 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultKeystoreService.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultKeystoreService.java
@@ -144,16 +144,23 @@ public class DefaultKeystoreService extends BaseKeystoreService implements
@Override
public KeyStore getSigningKeystore() throws KeystoreServiceException {
- File keyStoreFile = null;
- if (signingKeystoreName == null) {
+ return getSigningKeystore(null);
+ }
+
+ @Override
+ public KeyStore getSigningKeystore(String keystoreName) throws KeystoreServiceException {
+ File keyStoreFile;
+ if(keystoreName != null) {
+ keyStoreFile = new File(keyStoreDir + keystoreName + ".jks");
+ } else if (signingKeystoreName != null) {
+ keyStoreFile = new File(keyStoreDir + signingKeystoreName);
+ } else {
keyStoreFile = new File(keyStoreDir + GATEWAY_KEYSTORE);
}
- else {
- keyStoreFile = new File(keyStoreDir + signingKeystoreName);
- // make sure the keystore exists
- if (!keyStoreFile.exists()) {
- throw new KeystoreServiceException("Configured signing keystore does not exist.");
- }
+
+ // make sure the keystore exists
+ if (!keyStoreFile.exists()) {
+ throw new KeystoreServiceException("Configured signing keystore does not exist.");
}
readLock.lock();
try {
@@ -305,10 +312,15 @@ public class DefaultKeystoreService extends BaseKeystoreService implements
@Override
public Key getSigningKey(String alias, char[] passphrase) throws KeystoreServiceException {
+ return getSigningKey(null, alias, passphrase);
+ }
+
+ @Override
+ public Key getSigningKey(String keystoreName, String alias, char[] passphrase) throws KeystoreServiceException {
Key key = null;
readLock.lock();
try {
- KeyStore ks = getSigningKeystore();
+ KeyStore ks = getSigningKeystore(keystoreName);
if (passphrase == null) {
passphrase = masterService.getMasterSecret();
LOG.assumingKeyPassphraseIsMaster();
@@ -331,7 +343,7 @@ public class DefaultKeystoreService extends BaseKeystoreService implements
}
}
- public KeyStore getCredentialStoreForCluster(String clusterName)
+ public KeyStore getCredentialStoreForCluster(String clusterName)
throws KeystoreServiceException {
final File keyStoreFile = new File( keyStoreDir + clusterName + CREDENTIALS_SUFFIX );
readLock.lock();
http://git-wip-us.apache.org/repos/asf/knox/blob/2135bc22/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/DefaultTokenAuthorityService.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/DefaultTokenAuthorityService.java b/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/DefaultTokenAuthorityService.java
index ad8f999..b32e914 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/DefaultTokenAuthorityService.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/DefaultTokenAuthorityService.java
@@ -110,6 +110,13 @@ public class DefaultTokenAuthorityService implements JWTokenAuthority, Service {
@Override
public JWT issueToken(Principal p, List<String> audiences, String algorithm, long expires)
throws TokenServiceException {
+ return issueToken(p, audiences, algorithm, expires, null, null, null);
+ }
+
+ @Override
+ public JWT issueToken(Principal p, List<String> audiences, String algorithm, long expires,
+ String signingKeystoreName, String signingKeystoreAlias, char[] signingKeystorePassphrase)
+ throws TokenServiceException {
String[] claimArray = new String[4];
claimArray[0] = "KNOXSSO";
claimArray[1] = p.getName();
@@ -121,19 +128,18 @@ public class DefaultTokenAuthorityService implements JWTokenAuthority, Service {
claimArray[3] = String.valueOf(expires);
}
- JWT token = null;
+ JWT token;
if (SUPPORTED_SIG_ALGS.contains(algorithm)) {
token = new JWTToken(algorithm, claimArray, audiences);
- RSAPrivateKey key;
- char[] passphrase = null;
+ char[] passphrase;
try {
- passphrase = getSigningKeyPassphrase();
+ passphrase = getSigningKeyPassphrase(signingKeystorePassphrase);
} catch (AliasServiceException e) {
throw new TokenServiceException(e);
}
try {
- key = (RSAPrivateKey) ks.getSigningKey(getSigningKeyAlias(),
- passphrase);
+ RSAPrivateKey key = (RSAPrivateKey) ks.getSigningKey(signingKeystoreName,
+ getSigningKeyAlias(signingKeystoreAlias), passphrase);
JWSSigner signer = new RSASSASigner(key);
token.sign(signer);
} catch (KeystoreServiceException e) {
@@ -147,7 +153,10 @@ public class DefaultTokenAuthorityService implements JWTokenAuthority, Service {
return token;
}
- private char[] getSigningKeyPassphrase() throws AliasServiceException {
+ private char[] getSigningKeyPassphrase(char[] signingKeyPassphrase) throws AliasServiceException {
+ if(signingKeyPassphrase != null) {
+ return signingKeyPassphrase;
+ }
char[] phrase = as.getPasswordFromAliasForGateway(SIGNING_KEY_PASSPHRASE);
if (phrase == null) {
phrase = as.getGatewayIdentityPassphrase();
@@ -155,11 +164,14 @@ public class DefaultTokenAuthorityService implements JWTokenAuthority, Service {
return phrase;
}
- private String getSigningKeyAlias() {
- if (signingKeyAlias == null) {
- return "gateway-identity";
+ private String getSigningKeyAlias(String signingKeystoreAlias) {
+ if(signingKeystoreAlias != null) {
+ return signingKeystoreAlias;
+ }
+ if(signingKeyAlias != null) {
+ return signingKeyAlias;
}
- return signingKeyAlias;
+ return "gateway-identity";
}
@Override
@@ -171,11 +183,11 @@ public class DefaultTokenAuthorityService implements JWTokenAuthority, Service {
@Override
public boolean verifyToken(JWT token, RSAPublicKey publicKey)
throws TokenServiceException {
- boolean rc = false;
+ boolean rc;
PublicKey key;
try {
if (publicKey == null) {
- key = ks.getSigningKeystore().getCertificate(getSigningKeyAlias()).getPublicKey();
+ key = ks.getSigningKeystore().getCertificate(getSigningKeyAlias(signingKeyAlias)).getPublicKey();
}
else {
key = publicKey;
@@ -184,9 +196,7 @@ public class DefaultTokenAuthorityService implements JWTokenAuthority, Service {
// TODO: interrogate the token for issuer claim in order to determine the public key to use for verification
// consider jwk for specifying the key too
rc = token.verify(verifier);
- } catch (KeyStoreException e) {
- throw new TokenServiceException("Cannot verify token.", e);
- } catch (KeystoreServiceException e) {
+ } catch (KeyStoreException | KeystoreServiceException e) {
throw new TokenServiceException("Cannot verify token.", e);
}
return rc;
@@ -200,21 +210,18 @@ public class DefaultTokenAuthorityService implements JWTokenAuthority, Service {
}
signingKeyAlias = config.getSigningKeyAlias();
- @SuppressWarnings("unused")
RSAPrivateKey key;
- char[] passphrase = null;
+ char[] passphrase;
try {
passphrase = as.getPasswordFromAliasForGateway(SIGNING_KEY_PASSPHRASE);
if (passphrase != null) {
- key = (RSAPrivateKey) ks.getSigningKey(getSigningKeyAlias(),
+ key = (RSAPrivateKey) ks.getSigningKey(getSigningKeyAlias(signingKeyAlias),
passphrase);
if (key == null) {
throw new ServiceLifecycleException("Provisioned passphrase cannot be used to acquire signing key.");
}
}
- } catch (AliasServiceException e) {
- throw new ServiceLifecycleException("Provisioned signing key passphrase cannot be acquired.", e);
- } catch (KeystoreServiceException e) {
+ } catch (AliasServiceException | KeystoreServiceException e) {
throw new ServiceLifecycleException("Provisioned signing key passphrase cannot be acquired.", e);
}
}
http://git-wip-us.apache.org/repos/asf/knox/blob/2135bc22/gateway-server/src/test/java/org/apache/knox/gateway/services/token/impl/DefaultTokenAuthorityServiceTest.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/knox/gateway/services/token/impl/DefaultTokenAuthorityServiceTest.java b/gateway-server/src/test/java/org/apache/knox/gateway/services/token/impl/DefaultTokenAuthorityServiceTest.java
index f4d2d68..a51c79f 100644
--- a/gateway-server/src/test/java/org/apache/knox/gateway/services/token/impl/DefaultTokenAuthorityServiceTest.java
+++ b/gateway-server/src/test/java/org/apache/knox/gateway/services/token/impl/DefaultTokenAuthorityServiceTest.java
@@ -19,6 +19,8 @@ package org.apache.knox.gateway.services.token.impl;
import java.io.File;
import java.security.Principal;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Collections;
import java.util.HashMap;
import org.apache.knox.gateway.config.GatewayConfig;
@@ -251,4 +253,58 @@ public class DefaultTokenAuthorityServiceTest extends org.junit.Assert {
}
}
+ @Test
+ public void testTokenCreationCustomSigningKey() throws Exception {
+ /*
+ Generated testSigningKeyName.jks with the following commands:
+ cd gateway-server/src/test/resources/keystores/
+ keytool -genkey -alias testSigningKeyAlias -keyalg RSA -keystore testSigningKeyName.jks \
+ -storepass testSigningKeyPassphrase -keypass testSigningKeyPassphrase -keysize 2048 \
+ -dname 'CN=testSigningKey,OU=example,O=Apache,L=US,ST=CA,C=US' -noprompt
+ */
+
+ String customSigningKeyName = "testSigningKeyName";
+ String customSigningKeyAlias = "testSigningKeyAlias";
+ String customSigningKeyPassphrase = "testSigningKeyPassphrase";
+
+ Principal principal = EasyMock.createNiceMock(Principal.class);
+ EasyMock.expect(principal.getName()).andReturn("john.doe@example.com");
+
+ GatewayConfig config = EasyMock.createNiceMock(GatewayConfig.class);
+ String basedir = System.getProperty("basedir");
+ if (basedir == null) {
+ basedir = new File(".").getCanonicalPath();
+ }
+
+ EasyMock.expect(config.getGatewaySecurityDir()).andReturn(basedir + "/target/test-classes");
+ EasyMock.expect(config.getSigningKeystoreName()).andReturn("server-keystore.jks");
+ EasyMock.expect(config.getSigningKeyAlias()).andReturn("server").anyTimes();
+
+ MasterService ms = EasyMock.createNiceMock(MasterService.class);
+ EasyMock.expect(ms.getMasterSecret()).andReturn("horton".toCharArray());
+
+ AliasService as = EasyMock.createNiceMock(AliasService.class);
+ EasyMock.expect(as.getGatewayIdentityPassphrase()).andReturn("horton".toCharArray());
+
+ EasyMock.replay(principal, config, ms, as);
+
+ DefaultKeystoreService ks = new DefaultKeystoreService();
+ ks.setMasterService(ms);
+ ks.init(config, new HashMap<>());
+
+ DefaultTokenAuthorityService ta = new DefaultTokenAuthorityService();
+ ta.setAliasService(as);
+ ta.setKeystoreService(ks);
+ ta.init(config, new HashMap<>());
+
+ JWT token = ta.issueToken(principal, Collections.emptyList(), "RS256", -1,
+ customSigningKeyName, customSigningKeyAlias, customSigningKeyPassphrase.toCharArray());
+ assertEquals("KNOXSSO", token.getIssuer());
+ assertEquals("john.doe@example.com", token.getSubject());
+
+ RSAPublicKey customPublicKey = (RSAPublicKey)ks.getSigningKeystore(customSigningKeyName)
+ .getCertificate(customSigningKeyAlias).getPublicKey();
+ assertFalse(ta.verifyToken(token));
+ assertTrue(ta.verifyToken(token, customPublicKey));
+ }
}
http://git-wip-us.apache.org/repos/asf/knox/blob/2135bc22/gateway-server/src/test/resources/keystores/testSigningKeyName.jks
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/resources/keystores/testSigningKeyName.jks b/gateway-server/src/test/resources/keystores/testSigningKeyName.jks
new file mode 100644
index 0000000..d5e984a
Binary files /dev/null and b/gateway-server/src/test/resources/keystores/testSigningKeyName.jks differ
http://git-wip-us.apache.org/repos/asf/knox/blob/2135bc22/gateway-service-knoxsso/src/main/java/org/apache/knox/gateway/service/knoxsso/WebSSOResource.java
----------------------------------------------------------------------
diff --git a/gateway-service-knoxsso/src/main/java/org/apache/knox/gateway/service/knoxsso/WebSSOResource.java b/gateway-service-knoxsso/src/main/java/org/apache/knox/gateway/service/knoxsso/WebSSOResource.java
index 8f8002d..ab3702b 100644
--- a/gateway-service-knoxsso/src/main/java/org/apache/knox/gateway/service/knoxsso/WebSSOResource.java
+++ b/gateway-service-knoxsso/src/main/java/org/apache/knox/gateway/service/knoxsso/WebSSOResource.java
@@ -47,6 +47,8 @@ import javax.ws.rs.WebApplicationException;
import org.apache.knox.gateway.audit.log4j.audit.Log4jAuditor;
import org.apache.knox.gateway.i18n.messages.MessagesFactory;
import org.apache.knox.gateway.services.GatewayServices;
+import org.apache.knox.gateway.services.security.AliasService;
+import org.apache.knox.gateway.services.security.AliasServiceException;
import org.apache.knox.gateway.services.security.token.JWTokenAuthority;
import org.apache.knox.gateway.services.security.token.TokenServiceException;
import org.apache.knox.gateway.services.security.token.impl.JWT;
@@ -56,6 +58,7 @@ import org.apache.knox.gateway.util.WhitelistUtils;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static javax.ws.rs.core.MediaType.APPLICATION_XML;
+import static org.apache.knox.gateway.services.GatewayServices.GATEWAY_CLUSTER_ATTRIBUTE;
@Path( WebSSOResource.RESOURCE_PATH )
public class WebSSOResource {
@@ -68,6 +71,10 @@ public class WebSSOResource {
private static final String SSO_COOKIE_TOKEN_SIG_ALG = "knoxsso.token.sigalg";
private static final String SSO_COOKIE_TOKEN_WHITELIST_PARAM = "knoxsso.redirect.whitelist.regex";
+ private static final String SSO_SIGNINGKEY_KEYSTORE_NAME = "knoxsso.signingkey.keystore.name";
+ private static final String SSO_SIGNINGKEY_KEYSTORE_ALIAS = "knoxsso.signingkey.keystore.alias";
+ private static final String SSO_SIGNINGKEY_KEYSTORE_PASSPHRASE_ALIAS = "knoxsso.signingkey.keystore.passphrase.alias";
+
/* parameters expected by knoxsso */
private static final String SSO_EXPECTED_PARAM = "knoxsso.expected.params";
@@ -88,6 +95,7 @@ public class WebSSOResource {
private boolean enableSession = false;
private String signatureAlgorithm = "RS256";
private List<String> ssoExpectedparams = new ArrayList<>();
+ private String clusterName = null;
@Context
HttpServletRequest request;
@@ -100,19 +108,34 @@ public class WebSSOResource {
@PostConstruct
public void init() {
+ clusterName = String.valueOf(context.getAttribute(GATEWAY_CLUSTER_ATTRIBUTE));
+
+ handleCookieSetup();
+
+ String enableSessionStr = context.getInitParameter(SSO_ENABLE_SESSION_PARAM);
+ this.enableSession = Boolean.parseBoolean(enableSessionStr);
+
+ String sigAlg = context.getInitParameter(SSO_COOKIE_TOKEN_SIG_ALG);
+ if (sigAlg != null) {
+ signatureAlgorithm = sigAlg;
+ }
+
+ final String expectedParams = context.getInitParameter(SSO_EXPECTED_PARAM);
+ if (expectedParams != null) {
+ ssoExpectedparams = Arrays.asList(expectedParams.split(","));
+ }
+ }
- // configured cookieName
+ private void handleCookieSetup() {
cookieName = context.getInitParameter(SSO_COOKIE_NAME);
if (cookieName == null) {
cookieName = DEFAULT_SSO_COOKIE_NAME;
}
String secure = context.getInitParameter(SSO_COOKIE_SECURE_ONLY_INIT_PARAM);
- if (secure != null) {
- secureOnly = ("false".equals(secure) ? false : true);
- if (!secureOnly) {
- log.cookieSecureOnly(secureOnly);
- }
+ secureOnly = Boolean.parseBoolean(secure);
+ if (!secureOnly) {
+ log.cookieSecureOnly(secureOnly);
}
String age = context.getInitParameter(SSO_COOKIE_MAX_AGE_INIT_PARAM);
@@ -136,8 +159,8 @@ public class WebSSOResource {
String audiences = context.getInitParameter(SSO_COOKIE_TOKEN_AUDIENCES_PARAM);
if (audiences != null) {
String[] auds = audiences.split(",");
- for (int i = 0; i < auds.length; i++) {
- targetAudiences.add(auds[i].trim());
+ for (String aud : auds) {
+ targetAudiences.add(aud.trim());
}
}
@@ -154,19 +177,6 @@ public class WebSSOResource {
log.invalidTokenTTLEncountered(ttl);
}
}
-
- String enableSession = context.getInitParameter(SSO_ENABLE_SESSION_PARAM);
- this.enableSession = ("true".equals(enableSession));
-
- String sigAlg = context.getInitParameter(SSO_COOKIE_TOKEN_SIG_ALG);
- if (sigAlg != null) {
- signatureAlgorithm = sigAlg;
- }
-
- final String expectedParams = context.getInitParameter(SSO_EXPECTED_PARAM);
- if (expectedParams != null) {
- ssoExpectedparams = Arrays.asList(expectedParams.split(","));
- }
}
@GET
@@ -185,7 +195,7 @@ public class WebSSOResource {
GatewayServices services =
(GatewayServices) request.getServletContext().getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE);
boolean removeOriginalUrlCookie = true;
- String original = getCookieValue((HttpServletRequest) request, ORIGINAL_URL_COOKIE_NAME);
+ String original = getCookieValue(request, ORIGINAL_URL_COOKIE_NAME);
if (original == null) {
// in the case where there are no SAML redirects done before here
// we need to get it from the request parameters
@@ -218,17 +228,22 @@ public class WebSSOResource {
}
}
+ AliasService as = services.getService(GatewayServices.ALIAS_SERVICE);
JWTokenAuthority ts = services.getService(GatewayServices.TOKEN_SERVICE);
Principal p = request.getUserPrincipal();
try {
- JWT token = null;
- if (targetAudiences.isEmpty()) {
- token = ts.issueToken(p, signatureAlgorithm, getExpiry());
- } else {
- token = ts.issueToken(p, targetAudiences, signatureAlgorithm, getExpiry());
+ String signingKeystoreName = context.getInitParameter(SSO_SIGNINGKEY_KEYSTORE_NAME);
+ String signingKeystoreAlias = context.getInitParameter(SSO_SIGNINGKEY_KEYSTORE_ALIAS);
+ String signingKeystorePassphraseAlias = context.getInitParameter(SSO_SIGNINGKEY_KEYSTORE_PASSPHRASE_ALIAS);
+ char[] signingKeystorePassphrase = null;
+ if(signingKeystorePassphraseAlias != null) {
+ signingKeystorePassphrase = as.getPasswordFromAliasForCluster(clusterName, signingKeystorePassphraseAlias);
}
+ JWT token = ts.issueToken(p, targetAudiences, signatureAlgorithm, getExpiry(),
+ signingKeystoreName, signingKeystoreAlias, signingKeystorePassphrase);
+
// Coverity CID 1327959
if( token != null ) {
addJWTHadoopCookie( original, token );
@@ -246,8 +261,7 @@ public class WebSSOResource {
} catch (IOException e) {
log.unableToCloseOutputStream(e.getMessage(), Arrays.toString(e.getStackTrace()));
}
- }
- catch (TokenServiceException e) {
+ } catch (TokenServiceException| AliasServiceException e) {
log.unableToIssueToken(e);
}
URI location = null;
@@ -272,7 +286,7 @@ public class WebSSOResource {
private String getOriginalUrlFromQueryParams() {
String original = request.getParameter(ORIGINAL_URL_REQUEST_PARAM);
- StringBuffer buf = new StringBuffer(original);
+ StringBuilder buf = new StringBuilder(original);
boolean first = true;
@@ -310,7 +324,7 @@ public class WebSSOResource {
}
private long getExpiry() {
- long expiry = 0l;
+ long expiry;
if (tokenTTL == -1) {
expiry = -1;
}
http://git-wip-us.apache.org/repos/asf/knox/blob/2135bc22/gateway-service-knoxsso/src/test/java/org/apache/knox/gateway/service/knoxsso/WebSSOResourceTest.java
----------------------------------------------------------------------
diff --git a/gateway-service-knoxsso/src/test/java/org/apache/knox/gateway/service/knoxsso/WebSSOResourceTest.java b/gateway-service-knoxsso/src/test/java/org/apache/knox/gateway/service/knoxsso/WebSSOResourceTest.java
index d719404..e5f972d 100644
--- a/gateway-service-knoxsso/src/test/java/org/apache/knox/gateway/service/knoxsso/WebSSOResourceTest.java
+++ b/gateway-service-knoxsso/src/test/java/org/apache/knox/gateway/service/knoxsso/WebSSOResourceTest.java
@@ -20,7 +20,10 @@ package org.apache.knox.gateway.service.knoxsso;
import org.apache.http.HttpStatus;
import org.apache.knox.gateway.audit.log4j.audit.Log4jAuditor;
import org.apache.knox.gateway.config.GatewayConfig;
+import org.apache.knox.gateway.services.security.AliasService;
import org.apache.knox.gateway.util.RegExUtils;
+
+import static org.apache.knox.gateway.services.GatewayServices.GATEWAY_CLUSTER_ATTRIBUTE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -31,7 +34,6 @@ import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
-import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
@@ -73,21 +75,21 @@ import com.nimbusds.jose.crypto.RSASSAVerifier;
*/
public class WebSSOResourceTest {
- protected static RSAPublicKey publicKey;
- protected static RSAPrivateKey privateKey;
+ private static RSAPublicKey gatewayPublicKey;
+ private static RSAPrivateKey gatewayPrivateKey;
@BeforeClass
- public static void setup() throws Exception, NoSuchAlgorithmException {
+ public static void setup() throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
- KeyPair KPair = kpg.generateKeyPair();
+ KeyPair keyPair = kpg.generateKeyPair();
- publicKey = (RSAPublicKey) KPair.getPublic();
- privateKey = (RSAPrivateKey) KPair.getPrivate();
+ gatewayPublicKey = (RSAPublicKey) keyPair.getPublic();
+ gatewayPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
}
@Test
- public void testWhitelistMatching() throws Exception {
+ public void testWhitelistMatching() {
String whitelist = "^https?://.*example.com:8080/.*$;" +
"^https?://.*example.com/.*$;" +
"^https?://.*example2.com:\\d{0,9}/.*$;" +
@@ -144,7 +146,7 @@ public class WebSSOResourceTest {
HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
EasyMock.expect(request.getParameter("originalUrl")).andReturn("http://localhost:9080/service");
- EasyMock.expect(request.getParameterMap()).andReturn(Collections.<String,String[]>emptyMap());
+ EasyMock.expect(request.getParameterMap()).andReturn(Collections.emptyMap());
EasyMock.expect(request.getServletContext()).andReturn(context).anyTimes();
Principal principal = EasyMock.createNiceMock(Principal.class);
@@ -154,7 +156,7 @@ public class WebSSOResourceTest {
GatewayServices services = EasyMock.createNiceMock(GatewayServices.class);
EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(services);
- JWTokenAuthority authority = new TestJWTokenAuthority(publicKey, privateKey);
+ JWTokenAuthority authority = new TestJWTokenAuthority(gatewayPublicKey, gatewayPrivateKey);
EasyMock.expect(services.getService(GatewayServices.TOKEN_SERVICE)).andReturn(authority);
HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
@@ -196,7 +198,7 @@ public class WebSSOResourceTest {
HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
EasyMock.expect(request.getParameter("originalUrl")).andReturn("http://localhost:9080/service");
- EasyMock.expect(request.getParameterMap()).andReturn(Collections.<String,String[]>emptyMap());
+ EasyMock.expect(request.getParameterMap()).andReturn(Collections.emptyMap());
EasyMock.expect(request.getServletContext()).andReturn(context).anyTimes();
Principal principal = EasyMock.createNiceMock(Principal.class);
@@ -206,7 +208,7 @@ public class WebSSOResourceTest {
GatewayServices services = EasyMock.createNiceMock(GatewayServices.class);
EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(services);
- JWTokenAuthority authority = new TestJWTokenAuthority(publicKey, privateKey);
+ JWTokenAuthority authority = new TestJWTokenAuthority(gatewayPublicKey, gatewayPrivateKey);
EasyMock.expect(services.getService(GatewayServices.TOKEN_SERVICE)).andReturn(authority);
HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
@@ -254,7 +256,7 @@ public class WebSSOResourceTest {
HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
EasyMock.expect(request.getParameter("originalUrl")).andReturn("http://localhost:9080/service");
- EasyMock.expect(request.getParameterMap()).andReturn(Collections.<String,String[]>emptyMap());
+ EasyMock.expect(request.getParameterMap()).andReturn(Collections.emptyMap());
EasyMock.expect(request.getServletContext()).andReturn(context).anyTimes();
Principal principal = EasyMock.createNiceMock(Principal.class);
@@ -264,7 +266,7 @@ public class WebSSOResourceTest {
GatewayServices services = EasyMock.createNiceMock(GatewayServices.class);
EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(services);
- JWTokenAuthority authority = new TestJWTokenAuthority(publicKey, privateKey);
+ JWTokenAuthority authority = new TestJWTokenAuthority(gatewayPublicKey, gatewayPrivateKey);
EasyMock.expect(services.getService(GatewayServices.TOKEN_SERVICE)).andReturn(authority);
HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
@@ -313,7 +315,7 @@ public class WebSSOResourceTest {
HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
EasyMock.expect(request.getParameter("originalUrl")).andReturn("http://localhost:9080/service");
- EasyMock.expect(request.getParameterMap()).andReturn(Collections.<String,String[]>emptyMap());
+ EasyMock.expect(request.getParameterMap()).andReturn(Collections.emptyMap());
EasyMock.expect(request.getServletContext()).andReturn(context).anyTimes();
Principal principal = EasyMock.createNiceMock(Principal.class);
@@ -323,7 +325,7 @@ public class WebSSOResourceTest {
GatewayServices services = EasyMock.createNiceMock(GatewayServices.class);
EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(services);
- JWTokenAuthority authority = new TestJWTokenAuthority(publicKey, privateKey);
+ JWTokenAuthority authority = new TestJWTokenAuthority(gatewayPublicKey, gatewayPrivateKey);
EasyMock.expect(services.getService(GatewayServices.TOKEN_SERVICE)).andReturn(authority);
HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
@@ -366,7 +368,7 @@ public class WebSSOResourceTest {
HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
EasyMock.expect(request.getParameter("originalUrl")).andReturn("http://localhost:9080/service");
- EasyMock.expect(request.getParameterMap()).andReturn(Collections.<String,String[]>emptyMap());
+ EasyMock.expect(request.getParameterMap()).andReturn(Collections.emptyMap());
EasyMock.expect(request.getServletContext()).andReturn(context).anyTimes();
Principal principal = EasyMock.createNiceMock(Principal.class);
@@ -376,7 +378,7 @@ public class WebSSOResourceTest {
GatewayServices services = EasyMock.createNiceMock(GatewayServices.class);
EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(services);
- JWTokenAuthority authority = new TestJWTokenAuthority(publicKey, privateKey);
+ JWTokenAuthority authority = new TestJWTokenAuthority(gatewayPublicKey, gatewayPrivateKey);
EasyMock.expect(services.getService(GatewayServices.TOKEN_SERVICE)).andReturn(authority);
HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
@@ -422,7 +424,7 @@ public class WebSSOResourceTest {
HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
EasyMock.expect(request.getParameter("originalUrl")).andReturn("http://localhost:9080/service");
- EasyMock.expect(request.getParameterMap()).andReturn(Collections.<String,String[]>emptyMap());
+ EasyMock.expect(request.getParameterMap()).andReturn(Collections.emptyMap());
EasyMock.expect(request.getServletContext()).andReturn(context).anyTimes();
Principal principal = EasyMock.createNiceMock(Principal.class);
@@ -432,7 +434,7 @@ public class WebSSOResourceTest {
GatewayServices services = EasyMock.createNiceMock(GatewayServices.class);
EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(services);
- JWTokenAuthority authority = new TestJWTokenAuthority(publicKey, privateKey);
+ JWTokenAuthority authority = new TestJWTokenAuthority(gatewayPublicKey, gatewayPrivateKey);
EasyMock.expect(services.getService(GatewayServices.TOKEN_SERVICE)).andReturn(authority);
HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
@@ -480,7 +482,7 @@ public class WebSSOResourceTest {
HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
EasyMock.expect(request.getParameter("originalUrl")).andReturn("http://localhost:9080/service");
- EasyMock.expect(request.getParameterMap()).andReturn(Collections.<String,String[]>emptyMap());
+ EasyMock.expect(request.getParameterMap()).andReturn(Collections.emptyMap());
EasyMock.expect(request.getServletContext()).andReturn(context).anyTimes();
Principal principal = EasyMock.createNiceMock(Principal.class);
@@ -490,7 +492,7 @@ public class WebSSOResourceTest {
GatewayServices services = EasyMock.createNiceMock(GatewayServices.class);
EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(services);
- JWTokenAuthority authority = new TestJWTokenAuthority(publicKey, privateKey);
+ JWTokenAuthority authority = new TestJWTokenAuthority(gatewayPublicKey, gatewayPrivateKey);
EasyMock.expect(services.getService(GatewayServices.TOKEN_SERVICE)).andReturn(authority);
HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
@@ -537,7 +539,7 @@ public class WebSSOResourceTest {
HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
EasyMock.expect(request.getParameter("originalUrl")).andReturn("http://localhost:9080/service");
- EasyMock.expect(request.getParameterMap()).andReturn(Collections.<String,String[]>emptyMap());
+ EasyMock.expect(request.getParameterMap()).andReturn(Collections.emptyMap());
EasyMock.expect(request.getServletContext()).andReturn(context).anyTimes();
Principal principal = EasyMock.createNiceMock(Principal.class);
@@ -546,8 +548,8 @@ public class WebSSOResourceTest {
GatewayServices services = EasyMock.createNiceMock(GatewayServices.class);
EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(services);
-
- JWTokenAuthority authority = new TestJWTokenAuthority(publicKey, privateKey);
+
+ JWTokenAuthority authority = new TestJWTokenAuthority(gatewayPublicKey, gatewayPrivateKey);
EasyMock.expect(services.getService(GatewayServices.TOKEN_SERVICE)).andReturn(authority);
HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
@@ -601,7 +603,7 @@ public class WebSSOResourceTest {
EasyMock.expect(request.getParameter("originalUrl")).andReturn(
URLEncoder.encode("http://disallowedhost:9080/service", StandardCharsets.UTF_8.name()));
EasyMock.expect(request.getAttribute("targetServiceRole")).andReturn("KNOXSSO").anyTimes();
- EasyMock.expect(request.getParameterMap()).andReturn(Collections.<String,String[]>emptyMap());
+ EasyMock.expect(request.getParameterMap()).andReturn(Collections.emptyMap());
EasyMock.expect(request.getServletContext()).andReturn(context).anyTimes();
EasyMock.expect(request.getServerName()).andReturn("localhost").anyTimes();
@@ -612,7 +614,7 @@ public class WebSSOResourceTest {
GatewayServices services = EasyMock.createNiceMock(GatewayServices.class);
EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(services);
- JWTokenAuthority authority = new TestJWTokenAuthority(publicKey, privateKey);
+ JWTokenAuthority authority = new TestJWTokenAuthority(gatewayPublicKey, gatewayPrivateKey);
EasyMock.expect(services.getService(GatewayServices.TOKEN_SERVICE)).andReturn(authority);
HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
@@ -636,7 +638,6 @@ public class WebSSOResourceTest {
}
}
-
@Test
public void testTopologyDefinedWhitelist() throws Exception {
final String testServiceRole = "TEST";
@@ -659,7 +660,7 @@ public class WebSSOResourceTest {
HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
EasyMock.expect(request.getParameter("originalUrl")).andReturn("http://localhost:9080/service");
- EasyMock.expect(request.getParameterMap()).andReturn(Collections.<String,String[]>emptyMap());
+ EasyMock.expect(request.getParameterMap()).andReturn(Collections.emptyMap());
EasyMock.expect(request.getServletContext()).andReturn(context).anyTimes();
EasyMock.expect(request.getAttribute("targetServiceRole")).andReturn(testServiceRole).anyTimes();
EasyMock.expect(request.getServerName()).andReturn("localhost").anyTimes();
@@ -671,7 +672,7 @@ public class WebSSOResourceTest {
GatewayServices services = EasyMock.createNiceMock(GatewayServices.class);
EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(services);
- JWTokenAuthority authority = new TestJWTokenAuthority(publicKey, privateKey);
+ JWTokenAuthority authority = new TestJWTokenAuthority(gatewayPublicKey, gatewayPrivateKey);
EasyMock.expect(services.getService(GatewayServices.TOKEN_SERVICE)).andReturn(authority);
HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
@@ -694,7 +695,7 @@ public class WebSSOResourceTest {
}
@Test
- public void testExpectedKnoxSSOParams() throws Exception {
+ public void testExpectedKnoxSSOParams() {
final HashMap<String, String[]> paramMap = new HashMap<>();
paramMap.put("knoxtoken", new String[]{"eyJhbGciOiJSUzI1NiJ9.eyJzdWIiO"
@@ -723,7 +724,7 @@ public class WebSSOResourceTest {
GatewayServices services = EasyMock.createNiceMock(GatewayServices.class);
EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(services).anyTimes();
- JWTokenAuthority authority = new TestJWTokenAuthority(publicKey, privateKey);
+ JWTokenAuthority authority = new TestJWTokenAuthority(gatewayPublicKey, gatewayPrivateKey);
EasyMock.expect(services.getService(GatewayServices.TOKEN_SERVICE)).andReturn(authority).anyTimes();
HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
@@ -759,7 +760,7 @@ public class WebSSOResourceTest {
}
@Test
- public void testRedactToken() throws Exception {
+ public void testRedactToken() {
final String token = "eyJhbGciOiJSUzI1NiJ9."
+ "eyJzdWIiOiJhZG1pbjEiLCJpc3MiOiJLTk9YU1NPIiwiZXhwIjoxNTMwNzkwMjkxfQ."
@@ -787,7 +788,85 @@ public class WebSSOResourceTest {
"&originalUrl=http://www.local.com:8443/?gateway=one&knoxtoken", Log4jAuditor.maskTokenFromURL(fragment2));
assertEquals("/gateway/knoxsso/api/v1/websso?test=value"+
"&originalUrl=http://www.local.com:8443/?gateway=one&knoxtoken", Log4jAuditor.maskTokenFromURL(fragment3));
+ }
+
+ @Test
+ public void testCustomSigningKey() throws Exception {
+
+ String topologyName = "testCustomSigningKeyTopology";
+ String customSigningKeyName = "testSigningKeyName";
+ String customSigningKeyAlias = "testSigningKeyAlias";
+ String customSigningKeyPassphraseAlias = "testSigningKeyPassphraseAlias";
+ String customSigningKeyPassphrase = "testSigningKeyPassphrase";
+
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
+ kpg.initialize(1024);
+ KeyPair keyPair = kpg.generateKeyPair();
+ RSAPublicKey customPublicKey = (RSAPublicKey) keyPair.getPublic();
+ RSAPrivateKey customPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
+
+ ServletContext context = EasyMock.createNiceMock(ServletContext.class);
+ EasyMock.expect(context.getInitParameter("knoxsso.cookie.name")).andReturn(null);
+ EasyMock.expect(context.getInitParameter("knoxsso.cookie.secure.only")).andReturn(null);
+ EasyMock.expect(context.getInitParameter("knoxsso.cookie.max.age")).andReturn(null);
+ EasyMock.expect(context.getInitParameter("knoxsso.cookie.domain.suffix")).andReturn(null);
+ EasyMock.expect(context.getInitParameter("knoxsso.redirect.whitelist.regex")).andReturn(null);
+ EasyMock.expect(context.getInitParameter("knoxsso.token.audiences")).andReturn(null);
+ EasyMock.expect(context.getInitParameter("knoxsso.token.ttl")).andReturn(null);
+ EasyMock.expect(context.getInitParameter("knoxsso.enable.session")).andReturn(null);
+ EasyMock.expect(context.getInitParameter("knoxsso.signingkey.keystore.name"))
+ .andReturn(customSigningKeyName);
+ EasyMock.expect(context.getInitParameter("knoxsso.signingkey.keystore.alias"))
+ .andReturn(customSigningKeyAlias);
+ EasyMock.expect(context.getInitParameter("knoxsso.signingkey.keystore.passphrase.alias"))
+ .andReturn(customSigningKeyPassphraseAlias);
+ EasyMock.expect(context.getAttribute(GATEWAY_CLUSTER_ATTRIBUTE)).andReturn(topologyName);
+
+ HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
+ EasyMock.expect(request.getParameter("originalUrl")).andReturn("http://localhost:9080/service");
+ EasyMock.expect(request.getParameterMap()).andReturn(Collections.emptyMap());
+ EasyMock.expect(request.getServletContext()).andReturn(context).anyTimes();
+
+ Principal principal = EasyMock.createNiceMock(Principal.class);
+ EasyMock.expect(principal.getName()).andReturn("alice").anyTimes();
+ EasyMock.expect(request.getUserPrincipal()).andReturn(principal).anyTimes();
+
+ GatewayServices services = EasyMock.createNiceMock(GatewayServices.class);
+ EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(services);
+
+ TestJWTokenAuthority authority = new TestJWTokenAuthority(gatewayPublicKey, gatewayPrivateKey);
+ authority.addCustomSigningKey(customSigningKeyName, customSigningKeyAlias, customSigningKeyPassphrase.toCharArray(),
+ customPrivateKey);
+ EasyMock.expect(services.getService(GatewayServices.TOKEN_SERVICE)).andReturn(authority);
+
+ AliasService aliasService = EasyMock.createNiceMock(AliasService.class);
+ EasyMock.expect(aliasService.getPasswordFromAliasForCluster(topologyName, customSigningKeyPassphraseAlias))
+ .andReturn(customSigningKeyPassphrase.toCharArray());
+ EasyMock.expect(services.getService(GatewayServices.ALIAS_SERVICE)).andReturn(aliasService);
+
+ HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
+ ServletOutputStream outputStream = EasyMock.createNiceMock(ServletOutputStream.class);
+ CookieResponseWrapper responseWrapper = new CookieResponseWrapper(response, outputStream);
+
+ EasyMock.replay(principal, services, context, request, aliasService);
+
+ WebSSOResource webSSOResponse = new WebSSOResource();
+ webSSOResponse.request = request;
+ webSSOResponse.response = responseWrapper;
+ webSSOResponse.context = context;
+ webSSOResponse.init();
+ // Issue a token
+ webSSOResponse.doGet();
+
+ // Check the cookie
+ Cookie cookie = responseWrapper.getCookie("hadoop-jwt");
+ assertNotNull(cookie);
+
+ JWT parsedToken = new JWTToken(cookie.getValue());
+ assertEquals("alice", parsedToken.getSubject());
+ assertFalse(authority.verifyToken(parsedToken, gatewayPublicKey));
+ assertTrue(authority.verifyToken(parsedToken, customPublicKey));
}
/**
@@ -798,11 +877,7 @@ public class WebSSOResourceTest {
private ServletOutputStream outputStream;
private Map<String, Cookie> cookies = new HashMap<>();
- public CookieResponseWrapper(HttpServletResponse response) {
- super(response);
- }
-
- public CookieResponseWrapper(HttpServletResponse response, ServletOutputStream outputStream) {
+ CookieResponseWrapper(HttpServletResponse response, ServletOutputStream outputStream) {
super(response);
this.outputStream = outputStream;
}
@@ -818,22 +893,31 @@ public class WebSSOResourceTest {
cookies.put(cookie.getName(), cookie);
}
- public Cookie getCookie(String name) {
+ Cookie getCookie(String name) {
return cookies.get(name);
}
-
}
private static class TestJWTokenAuthority implements JWTokenAuthority {
-
private RSAPublicKey publicKey;
private RSAPrivateKey privateKey;
+ private Map<String, Map<String,Object>> customSigningKeys = new HashMap<>();
- public TestJWTokenAuthority(RSAPublicKey publicKey, RSAPrivateKey privateKey) {
+ TestJWTokenAuthority(RSAPublicKey publicKey, RSAPrivateKey privateKey) {
this.publicKey = publicKey;
this.privateKey = privateKey;
}
+ void addCustomSigningKey(String signingKeystoreName, String signingKeystoreAlias,
+ char[] signingKeystorePassphrase, RSAPrivateKey customPrivateKey) {
+
+ Map<String, Object> signingKey = new HashMap<>();
+ signingKey.put("alias", signingKeystoreAlias);
+ signingKey.put("passphrase", signingKeystorePassphrase);
+ signingKey.put("privateKey", customPrivateKey);
+ customSigningKeys.put(signingKeystoreName, signingKey);
+ }
+
@Override
public JWT issueToken(Subject subject, String algorithm)
throws TokenServiceException {
@@ -854,7 +938,7 @@ public class WebSSOResourceTest {
}
@Override
- public boolean verifyToken(JWT token) throws TokenServiceException {
+ public boolean verifyToken(JWT token) {
JWSVerifier verifier = new RSASSAVerifier(publicKey);
return token.verify(verifier);
}
@@ -872,7 +956,14 @@ public class WebSSOResourceTest {
@Override
public JWT issueToken(Principal p, List<String> audiences, String algorithm,
- long expires) throws TokenServiceException {
+ long expires) throws TokenServiceException {
+ return issueToken(p, audiences, algorithm, expires, null, null, null);
+ }
+
+ @Override
+ public JWT issueToken(Principal p, List<String> audiences, String algorithm, long expires,
+ String signingKeystoreName, String signingKeystoreAlias, char[] signingKeystorePassphrase)
+ throws TokenServiceException {
String[] claimArray = new String[4];
claimArray[0] = "KNOXSSO";
claimArray[1] = p.getName();
@@ -884,24 +975,36 @@ public class WebSSOResourceTest {
}
JWT token = new JWTToken(algorithm, claimArray, audiences);
+ RSAPrivateKey privateKey = getPrivateKey(signingKeystoreName, signingKeystoreAlias, signingKeystorePassphrase);
JWSSigner signer = new RSASSASigner(privateKey);
token.sign(signer);
return token;
}
+ private RSAPrivateKey getPrivateKey(String signingKeystoreName, String signingKeystoreAlias,
+ char[] signingKeystorePassphrase) throws TokenServiceException {
+ if(signingKeystoreName != null) {
+ Map<String, Object> signingKey = customSigningKeys.get(signingKeystoreName);
+ if(signingKey == null || !signingKey.get("alias").equals(signingKeystoreAlias) ||
+ !Arrays.equals((char[])signingKey.get("passphrase"), signingKeystorePassphrase)) {
+ throw new TokenServiceException("Invalid alias or passphrase");
+ }
+ return (RSAPrivateKey)signingKey.get("privateKey");
+ }
+ return privateKey;
+ }
+
@Override
public JWT issueToken(Principal p, String algorithm, long expiry)
throws TokenServiceException {
- return issueToken(p, Collections.<String>emptyList(), algorithm, expiry);
+ return issueToken(p, Collections.emptyList(), algorithm, expiry);
}
@Override
- public boolean verifyToken(JWT token, RSAPublicKey publicKey) throws TokenServiceException {
+ public boolean verifyToken(JWT token, RSAPublicKey publicKey) {
JWSVerifier verifier = new RSASSAVerifier(publicKey);
return token.verify(verifier);
}
-
}
-
}
http://git-wip-us.apache.org/repos/asf/knox/blob/2135bc22/gateway-service-knoxtoken/src/test/java/org/apache/knox/gateway/service/knoxtoken/TokenServiceResourceTest.java
----------------------------------------------------------------------
diff --git a/gateway-service-knoxtoken/src/test/java/org/apache/knox/gateway/service/knoxtoken/TokenServiceResourceTest.java b/gateway-service-knoxtoken/src/test/java/org/apache/knox/gateway/service/knoxtoken/TokenServiceResourceTest.java
index decef70..18a645f 100644
--- a/gateway-service-knoxtoken/src/test/java/org/apache/knox/gateway/service/knoxtoken/TokenServiceResourceTest.java
+++ b/gateway-service-knoxtoken/src/test/java/org/apache/knox/gateway/service/knoxtoken/TokenServiceResourceTest.java
@@ -24,7 +24,6 @@ import com.nimbusds.jose.crypto.RSASSAVerifier;
import org.apache.knox.gateway.security.PrimaryPrincipal;
import org.apache.knox.gateway.services.GatewayServices;
import org.apache.knox.gateway.services.security.token.JWTokenAuthority;
-import org.apache.knox.gateway.services.security.token.TokenServiceException;
import org.apache.knox.gateway.services.security.token.impl.JWT;
import org.apache.knox.gateway.services.security.token.impl.JWTToken;
import org.easymock.EasyMock;
@@ -38,7 +37,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.Response;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
-import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
@@ -60,11 +58,11 @@ import static org.junit.Assert.assertTrue;
*/
public class TokenServiceResourceTest {
- protected static RSAPublicKey publicKey;
- protected static RSAPrivateKey privateKey;
+ private static RSAPublicKey publicKey;
+ private static RSAPrivateKey privateKey;
@BeforeClass
- public static void setup() throws Exception, NoSuchAlgorithmException {
+ public static void setup() throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
KeyPair KPair = kpg.generateKeyPair();
@@ -74,25 +72,25 @@ public class TokenServiceResourceTest {
}
@Test
- public void testTokenService() throws Exception {
+ public void testTokenService() {
Assert.assertTrue(true);
}
@Test
- public void testClientData() throws Exception {
+ public void testClientData() {
TokenResource tr = new TokenResource();
Map<String,Object> clientDataMap = new HashMap<>();
tr.addClientDataToMap("cookie.name=hadoop-jwt,test=value".split(","), clientDataMap);
- Assert.assertTrue(clientDataMap.size() == 2);
+ Assert.assertEquals(2, clientDataMap.size());
clientDataMap = new HashMap<>();
tr.addClientDataToMap("cookie.name=hadoop-jwt".split(","), clientDataMap);
- Assert.assertTrue(clientDataMap.size() == 1);
+ Assert.assertEquals(1, clientDataMap.size());
clientDataMap = new HashMap<>();
tr.addClientDataToMap("".split(","), clientDataMap);
- Assert.assertTrue(clientDataMap.size() == 0);
+ Assert.assertEquals(0, clientDataMap.size());
}
@Test
@@ -631,39 +629,36 @@ public class TokenServiceResourceTest {
private RSAPublicKey publicKey;
private RSAPrivateKey privateKey;
- public TestJWTokenAuthority(RSAPublicKey publicKey, RSAPrivateKey privateKey) {
+ TestJWTokenAuthority(RSAPublicKey publicKey, RSAPrivateKey privateKey) {
this.publicKey = publicKey;
this.privateKey = privateKey;
}
@Override
- public JWT issueToken(Subject subject, String algorithm)
- throws TokenServiceException {
+ public JWT issueToken(Subject subject, String algorithm) {
Principal p = (Principal) subject.getPrincipals().toArray()[0];
return issueToken(p, algorithm);
}
@Override
- public JWT issueToken(Principal p, String algorithm)
- throws TokenServiceException {
+ public JWT issueToken(Principal p, String algorithm) {
return issueToken(p, null, algorithm);
}
@Override
- public JWT issueToken(Principal p, String audience, String algorithm)
- throws TokenServiceException {
+ public JWT issueToken(Principal p, String audience, String algorithm) {
return issueToken(p, audience, algorithm, -1);
}
@Override
- public boolean verifyToken(JWT token) throws TokenServiceException {
+ public boolean verifyToken(JWT token) {
JWSVerifier verifier = new RSASSAVerifier(publicKey);
return token.verify(verifier);
}
@Override
public JWT issueToken(Principal p, String audience, String algorithm,
- long expires) throws TokenServiceException {
+ long expires) {
ArrayList<String> audiences = null;
if (audience != null) {
audiences = new ArrayList<>();
@@ -673,8 +668,13 @@ public class TokenServiceResourceTest {
}
@Override
- public JWT issueToken(Principal p, List<String> audiences, String algorithm,
- long expires) throws TokenServiceException {
+ public JWT issueToken(Principal p, List<String> audiences, String algorithm, long expires,
+ String signingkeyName, String signingkeyAlias, char[] signingkeyPassphrase) {
+ return issueToken(p, audiences, algorithm, expires);
+ }
+
+ @Override
+ public JWT issueToken(Principal p, List<String> audiences, String algorithm, long expires) {
String[] claimArray = new String[4];
claimArray[0] = "KNOXSSO";
claimArray[1] = p.getName();
@@ -693,18 +693,14 @@ public class TokenServiceResourceTest {
}
@Override
- public JWT issueToken(Principal p, String algorithm, long expiry)
- throws TokenServiceException {
- return issueToken(p, Collections.<String>emptyList(), algorithm, expiry);
+ public JWT issueToken(Principal p, String algorithm, long expiry) {
+ return issueToken(p, Collections.emptyList(), algorithm, expiry);
}
@Override
- public boolean verifyToken(JWT token, RSAPublicKey publicKey) throws TokenServiceException {
+ public boolean verifyToken(JWT token, RSAPublicKey publicKey) {
JWSVerifier verifier = new RSASSAVerifier(publicKey);
return token.verify(verifier);
}
-
}
-
-
}
http://git-wip-us.apache.org/repos/asf/knox/blob/2135bc22/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/KeystoreService.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/KeystoreService.java b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/KeystoreService.java
index 30dfe31..0467565 100644
--- a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/KeystoreService.java
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/KeystoreService.java
@@ -22,33 +22,37 @@ import java.security.KeyStore;
public interface KeystoreService {
- public void createKeystoreForGateway() throws KeystoreServiceException;
+ void createKeystoreForGateway() throws KeystoreServiceException;
- public void addSelfSignedCertForGateway(String alias, char[] passphrase) throws KeystoreServiceException;
+ void addSelfSignedCertForGateway(String alias, char[] passphrase) throws KeystoreServiceException;
void addSelfSignedCertForGateway(String alias, char[] passphrase, String hostname) throws KeystoreServiceException;
- public KeyStore getKeystoreForGateway() throws KeystoreServiceException;
+ KeyStore getKeystoreForGateway() throws KeystoreServiceException;
- public KeyStore getSigningKeystore() throws KeystoreServiceException;
+ KeyStore getSigningKeystore() throws KeystoreServiceException;
- public Key getKeyForGateway(String alias, char[] passphrase) throws KeystoreServiceException;
+ KeyStore getSigningKeystore(String keystoreName) throws KeystoreServiceException;
- public Key getSigningKey(String alias, char[] passphrase) throws KeystoreServiceException;
+ Key getKeyForGateway(String alias, char[] passphrase) throws KeystoreServiceException;
- public void createCredentialStoreForCluster(String clusterName) throws KeystoreServiceException;
-
- public boolean isCredentialStoreForClusterAvailable(String clusterName) throws KeystoreServiceException;
+ Key getSigningKey(String alias, char[] passphrase) throws KeystoreServiceException;
- public boolean isKeystoreForGatewayAvailable() throws KeystoreServiceException;
-
- public KeyStore getCredentialStoreForCluster(String clusterName) throws KeystoreServiceException;
+ Key getSigningKey(String keystoreName, String alias, char[] passphrase) throws KeystoreServiceException;
+
+ void createCredentialStoreForCluster(String clusterName) throws KeystoreServiceException;
+
+ boolean isCredentialStoreForClusterAvailable(String clusterName) throws KeystoreServiceException;
+
+ boolean isKeystoreForGatewayAvailable() throws KeystoreServiceException;
+
+ KeyStore getCredentialStoreForCluster(String clusterName) throws KeystoreServiceException;
- public void addCredentialForCluster(String clusterName, String alias, String key) throws KeystoreServiceException;
+ void addCredentialForCluster(String clusterName, String alias, String key) throws KeystoreServiceException;
- public void removeCredentialForCluster(String clusterName, String alias) throws KeystoreServiceException;
+ void removeCredentialForCluster(String clusterName, String alias) throws KeystoreServiceException;
- public char[] getCredentialForCluster(String clusterName, String alias) throws KeystoreServiceException;
+ char[] getCredentialForCluster(String clusterName, String alias) throws KeystoreServiceException;
- public String getKeystorePath();
+ String getKeystorePath();
}
http://git-wip-us.apache.org/repos/asf/knox/blob/2135bc22/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/JWTokenAuthority.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/JWTokenAuthority.java b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/JWTokenAuthority.java
index 6a5949b..2f71c2b 100644
--- a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/JWTokenAuthority.java
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/JWTokenAuthority.java
@@ -46,6 +46,10 @@ public interface JWTokenAuthority {
JWT issueToken(Principal p, String audience, String algorithm,
long expires) throws TokenServiceException;
- JWT issueToken(Principal p, List<String> audience, String algorithm,
+ JWT issueToken(Principal p, List<String> audiences, String algorithm,
long expires) throws TokenServiceException;
+
+ JWT issueToken(Principal p, List<String> audiences, String algorithm, long expires,
+ String signingKeystoreName, String signingKeystoreAlias, char[] signingKeystorePassphrase)
+ throws TokenServiceException;
}
\ No newline at end of file