Add extra workspace existence check before creating keypair
parent
0ec95375e0
commit
f838ea5a60
|
|
@ -43,7 +43,6 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.api.core.model.workspace.config.MachineConfig;
|
||||
import org.eclipse.che.api.core.model.workspace.config.ServerConfig;
|
||||
import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
|
||||
|
|
@ -52,6 +51,7 @@ import org.eclipse.che.api.workspace.server.spi.InternalInfrastructureException;
|
|||
import org.eclipse.che.api.workspace.server.spi.environment.InternalMachineConfig;
|
||||
import org.eclipse.che.commons.lang.Size;
|
||||
import org.eclipse.che.multiuser.machine.authentication.server.signature.SignatureKeyManager;
|
||||
import org.eclipse.che.multiuser.machine.authentication.server.signature.SignatureKeyManagerException;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.server.ServerServiceBuilder;
|
||||
import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.jwtproxy.factory.JwtProxyConfigBuilderFactory;
|
||||
|
|
@ -211,8 +211,8 @@ public class JwtProxyProvisioner {
|
|||
|
||||
KeyPair keyPair;
|
||||
try {
|
||||
keyPair = signatureKeyManager.getKeyPair(identity.getWorkspaceId());
|
||||
} catch (ServerException e) {
|
||||
keyPair = signatureKeyManager.getOrCreateKeyPair(identity.getWorkspaceId());
|
||||
} catch (SignatureKeyManagerException e) {
|
||||
throw new InternalInfrastructureException(
|
||||
"Signature key pair for machine authentication cannot be retrieved. Reason: "
|
||||
+ e.getMessage());
|
||||
|
|
|
|||
|
|
@ -75,7 +75,8 @@ public class JwtProxyProvisionerTest {
|
|||
|
||||
@BeforeMethod
|
||||
public void setUp() throws Exception {
|
||||
when(signatureKeyManager.getKeyPair(anyString())).thenReturn(new KeyPair(publicKey, null));
|
||||
when(signatureKeyManager.getOrCreateKeyPair(anyString()))
|
||||
.thenReturn(new KeyPair(publicKey, null));
|
||||
when(publicKey.getEncoded()).thenReturn("publickey".getBytes());
|
||||
|
||||
when(configBuilderFactory.create(any()))
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ public class KeycloakEnvironmentInitalizationFilterTest {
|
|||
parser.setAccessible(true);
|
||||
parser.set(filter, jwtParser);
|
||||
final KeyPair kp = new KeyPair(mock(PublicKey.class), mock(PrivateKey.class));
|
||||
when(keyManager.getKeyPair(anyString())).thenReturn(kp);
|
||||
when(keyManager.getOrCreateKeyPair(anyString())).thenReturn(kp);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -90,10 +90,6 @@
|
|||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-api-workspace-shared</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-commons-annotations</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-commons-auth</artifactId>
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ import org.eclipse.che.commons.env.EnvironmentContext;
|
|||
import org.eclipse.che.commons.subject.Subject;
|
||||
import org.eclipse.che.commons.subject.SubjectImpl;
|
||||
import org.eclipse.che.multiuser.api.permission.server.PermissionChecker;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Handles requests that comes from machines with specific machine token.
|
||||
|
|
@ -53,6 +55,8 @@ import org.eclipse.che.multiuser.api.permission.server.PermissionChecker;
|
|||
@Singleton
|
||||
public class MachineLoginFilter implements Filter {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MachineLoginFilter.class);
|
||||
|
||||
private final RequestTokenExtractor tokenExtractor;
|
||||
private final UserManager userManager;
|
||||
private final PermissionChecker permissionChecker;
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ import io.jsonwebtoken.SigningKeyResolverAdapter;
|
|||
import java.security.Key;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.multiuser.machine.authentication.server.signature.SignatureKeyManager;
|
||||
import org.eclipse.che.multiuser.machine.authentication.server.signature.SignatureKeyManagerException;
|
||||
|
||||
/** Resolves signing key pair based on workspace Id claim of token. */
|
||||
@Singleton
|
||||
|
|
@ -46,9 +46,9 @@ public class MachineSigningKeyResolver extends SigningKeyResolverAdapter {
|
|||
"Unable to fetch signature key pair: no workspace id present in token");
|
||||
}
|
||||
try {
|
||||
return keyManager.getKeyPair(wsId).getPublic();
|
||||
} catch (ServerException e) {
|
||||
throw new JwtException("Unable to fetch signature key pair:" + e.getMessage());
|
||||
return keyManager.getOrCreateKeyPair(wsId).getPublic();
|
||||
} catch (SignatureKeyManagerException e) {
|
||||
throw new JwtException("Unable to fetch signature key pair:" + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,9 @@ import org.eclipse.che.api.core.NotFoundException;
|
|||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.api.core.model.user.User;
|
||||
import org.eclipse.che.api.user.server.UserManager;
|
||||
import org.eclipse.che.api.workspace.server.token.MachineTokenException;
|
||||
import org.eclipse.che.multiuser.machine.authentication.server.signature.SignatureKeyManager;
|
||||
import org.eclipse.che.multiuser.machine.authentication.server.signature.SignatureKeyManagerException;
|
||||
import org.eclipse.che.multiuser.machine.authentication.shared.Constants;
|
||||
|
||||
/**
|
||||
|
|
@ -66,9 +68,9 @@ public class MachineTokenRegistry {
|
|||
* @param userId id of user to get token
|
||||
* @param workspaceId id of workspace to get token
|
||||
* @return machine security token for for given user and workspace
|
||||
* @throws IllegalStateException when user with given id not found or any errors occurs
|
||||
* @throws MachineTokenException when user with given id not found or any errors occurs
|
||||
*/
|
||||
public String getOrCreateToken(String userId, String workspaceId) {
|
||||
public String getOrCreateToken(String userId, String workspaceId) throws MachineTokenException {
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
final Map<String, String> wsRow = tokens.row(workspaceId);
|
||||
|
|
@ -77,41 +79,43 @@ public class MachineTokenRegistry {
|
|||
token = createToken(userId, workspaceId);
|
||||
}
|
||||
return token;
|
||||
} catch (NotFoundException | ServerException ex) {
|
||||
throw new IllegalStateException(
|
||||
format(
|
||||
"Failed to generate machine token for user '%s' and workspace '%s'. Cause: '%s'",
|
||||
userId, workspaceId, ex.getMessage()),
|
||||
ex);
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/** Creates new token with given data. */
|
||||
private String createToken(String userId, String workspaceId)
|
||||
throws NotFoundException, ServerException {
|
||||
final PrivateKey privateKey = signatureKeyManager.getKeyPair(workspaceId).getPrivate();
|
||||
final User user = userManager.getById(userId);
|
||||
final Map<String, Object> header = new HashMap<>(2);
|
||||
header.put("kind", MACHINE_TOKEN_KIND);
|
||||
header.put("kid", workspaceId);
|
||||
final Map<String, Object> claims = new HashMap<>();
|
||||
// to ensure that each token is unique
|
||||
claims.put(Claims.ID, UUID.randomUUID().toString());
|
||||
claims.put(Constants.USER_ID_CLAIM, userId);
|
||||
claims.put(Constants.USER_NAME_CLAIM, user.getName());
|
||||
claims.put(Constants.WORKSPACE_ID_CLAIM, workspaceId);
|
||||
// jwtproxy required claims
|
||||
claims.put(Claims.ISSUER, "wsmaster");
|
||||
claims.put(Claims.AUDIENCE, workspaceId);
|
||||
claims.put(Claims.EXPIRATION, Instant.now().plus(365, DAYS).getEpochSecond());
|
||||
claims.put(Claims.NOT_BEFORE, -1); // always
|
||||
claims.put(Claims.ISSUED_AT, Instant.now().getEpochSecond());
|
||||
final String token =
|
||||
Jwts.builder().setClaims(claims).setHeader(header).signWith(RS256, privateKey).compact();
|
||||
tokens.put(workspaceId, userId, token);
|
||||
return token;
|
||||
private String createToken(String userId, String workspaceId) throws MachineTokenException {
|
||||
try {
|
||||
final PrivateKey privateKey =
|
||||
signatureKeyManager.getOrCreateKeyPair(workspaceId).getPrivate();
|
||||
final User user = userManager.getById(userId);
|
||||
final Map<String, Object> header = new HashMap<>(2);
|
||||
header.put("kind", MACHINE_TOKEN_KIND);
|
||||
header.put("kid", workspaceId);
|
||||
final Map<String, Object> claims = new HashMap<>();
|
||||
// to ensure that each token is unique
|
||||
claims.put(Claims.ID, UUID.randomUUID().toString());
|
||||
claims.put(Constants.USER_ID_CLAIM, userId);
|
||||
claims.put(Constants.USER_NAME_CLAIM, user.getName());
|
||||
claims.put(Constants.WORKSPACE_ID_CLAIM, workspaceId);
|
||||
// jwtproxy required claims
|
||||
claims.put(Claims.ISSUER, "wsmaster");
|
||||
claims.put(Claims.AUDIENCE, workspaceId);
|
||||
claims.put(Claims.EXPIRATION, Instant.now().plus(365, DAYS).getEpochSecond());
|
||||
claims.put(Claims.NOT_BEFORE, -1); // always
|
||||
claims.put(Claims.ISSUED_AT, Instant.now().getEpochSecond());
|
||||
final String token =
|
||||
Jwts.builder().setClaims(claims).setHeader(header).signWith(RS256, privateKey).compact();
|
||||
tokens.put(workspaceId, userId, token);
|
||||
return token;
|
||||
} catch (SignatureKeyManagerException | NotFoundException | ServerException ex) {
|
||||
throw new MachineTokenException(
|
||||
format(
|
||||
"Failed to generate machine token for user '%s' and workspace '%s'. Cause: '%s'",
|
||||
userId, workspaceId, ex.getMessage()),
|
||||
ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -15,9 +15,6 @@ import static org.eclipse.che.api.core.model.workspace.WorkspaceStatus.STOPPED;
|
|||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
|
|
@ -28,8 +25,6 @@ import java.security.spec.EncodedKeySpec;
|
|||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
|
@ -40,7 +35,6 @@ import org.eclipse.che.api.core.ServerException;
|
|||
import org.eclipse.che.api.core.notification.EventService;
|
||||
import org.eclipse.che.api.core.notification.EventSubscriber;
|
||||
import org.eclipse.che.api.workspace.shared.dto.event.WorkspaceStatusEvent;
|
||||
import org.eclipse.che.commons.annotation.Nullable;
|
||||
import org.eclipse.che.core.db.DBInitializer;
|
||||
import org.eclipse.che.multiuser.machine.authentication.server.signature.model.impl.SignatureKeyPairImpl;
|
||||
import org.eclipse.che.multiuser.machine.authentication.server.signature.spi.SignatureKeyDao;
|
||||
|
|
@ -72,8 +66,6 @@ public class SignatureKeyManager {
|
|||
@SuppressWarnings("unused")
|
||||
private DBInitializer dbInitializer;
|
||||
|
||||
private LoadingCache<String, KeyPair> cachedPair;
|
||||
|
||||
@Inject
|
||||
public SignatureKeyManager(
|
||||
@Named("che.auth.signature_key_size") int keySize,
|
||||
|
|
@ -84,19 +76,6 @@ public class SignatureKeyManager {
|
|||
this.algorithm = algorithm;
|
||||
this.eventService = eventService;
|
||||
this.signatureKeyDao = signatureKeyDao;
|
||||
|
||||
this.cachedPair =
|
||||
CacheBuilder.newBuilder()
|
||||
.maximumSize(100)
|
||||
.expireAfterAccess(2, TimeUnit.HOURS)
|
||||
.build(
|
||||
new CacheLoader<String, KeyPair>() {
|
||||
@Override
|
||||
public KeyPair load(String key) throws Exception {
|
||||
return loadKeyPair(key);
|
||||
}
|
||||
});
|
||||
|
||||
this.workspaceEventsSubscriber =
|
||||
new EventSubscriber<WorkspaceStatusEvent>() {
|
||||
@Override
|
||||
|
|
@ -108,21 +87,34 @@ public class SignatureKeyManager {
|
|||
};
|
||||
}
|
||||
|
||||
/** Returns cached instance of {@link KeyPair} or null when failed to load key pair. */
|
||||
@Nullable
|
||||
public KeyPair getKeyPair(String workspaceId) throws ServerException {
|
||||
/**
|
||||
* Returns instance of {@link KeyPair} for given workspace.
|
||||
*
|
||||
* @throws SignatureKeyManagerException when stored keypair is incorrect (e.g. has bad algorithm
|
||||
* or keyspec) or other error
|
||||
*/
|
||||
public KeyPair getOrCreateKeyPair(String workspaceId) throws SignatureKeyManagerException {
|
||||
SignatureKeyPair keyPair;
|
||||
try {
|
||||
return cachedPair.get(workspaceId);
|
||||
} catch (ExecutionException e) {
|
||||
throw new ServerException(e.getCause());
|
||||
try {
|
||||
keyPair = signatureKeyDao.get(workspaceId);
|
||||
} catch (NotFoundException e) {
|
||||
keyPair = generateKeyPair(workspaceId);
|
||||
}
|
||||
} catch (NoSuchAlgorithmException | ServerException | ConflictException ex) {
|
||||
LOG.error(
|
||||
"Failed to load signature keys for ws {}. Cause: {}", workspaceId, ex.getMessage());
|
||||
throw new SignatureKeyManagerException(ex.getMessage(), ex);
|
||||
}
|
||||
return toJavaKeyPair(keyPair);
|
||||
}
|
||||
|
||||
/** Removes key pair from cache and DB. */
|
||||
public void removeKeyPair(String workspaceId) {
|
||||
@VisibleForTesting
|
||||
void removeKeyPair(String workspaceId) {
|
||||
try {
|
||||
cachedPair.invalidate(workspaceId);
|
||||
signatureKeyDao.remove(workspaceId);
|
||||
LOG.debug("Removed signature key pair for ws id {}.", workspaceId);
|
||||
} catch (ServerException e) {
|
||||
LOG.error(
|
||||
"Unable to cleanup machine token signature keypairs for ws {}. Cause: {}",
|
||||
|
|
@ -131,64 +123,31 @@ public class SignatureKeyManager {
|
|||
}
|
||||
}
|
||||
|
||||
/** Loads signature key pair if no existing keys found then stores a newly generated key pair. */
|
||||
@PostConstruct
|
||||
@VisibleForTesting
|
||||
KeyPair loadKeyPair(String workspaceId) throws ServerException, ConflictException {
|
||||
SignatureKeyPair generateKeyPair(String workspaceId)
|
||||
throws NoSuchAlgorithmException, ServerException, ConflictException {
|
||||
try {
|
||||
return toJavaKeyPair(signatureKeyDao.get(workspaceId));
|
||||
} catch (NotFoundException nfe) {
|
||||
try {
|
||||
return toJavaKeyPair(signatureKeyDao.create(generateKeyPair(workspaceId)));
|
||||
} catch (ConflictException | ServerException ex) {
|
||||
LOG.error(
|
||||
"Failed to store signature keys for ws {}. Cause: {}", workspaceId, ex.getMessage());
|
||||
throw ex;
|
||||
}
|
||||
} catch (ServerException ex) {
|
||||
KeyPairGenerator kpg = KeyPairGenerator.getInstance(algorithm);
|
||||
kpg.initialize(keySize);
|
||||
final KeyPair pair = kpg.generateKeyPair();
|
||||
final SignatureKeyPairImpl kp =
|
||||
new SignatureKeyPairImpl(workspaceId, pair.getPublic(), pair.getPrivate());
|
||||
LOG.debug(
|
||||
"Generated signature key pair with ws id {} and algorithm {}.",
|
||||
kp.getWorkspaceId(),
|
||||
algorithm);
|
||||
return signatureKeyDao.create(kp);
|
||||
} catch (NoSuchAlgorithmException | ConflictException | ServerException ex) {
|
||||
LOG.error(
|
||||
"Failed to load signature keys for ws {}. Cause: {}", workspaceId, ex.getMessage());
|
||||
"Unable to generate signature keypair for ws {}. Cause: {}",
|
||||
workspaceId,
|
||||
ex.getMessage());
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
SignatureKeyPairImpl generateKeyPair(String workspaceId) throws ServerException {
|
||||
final KeyPairGenerator kpg;
|
||||
try {
|
||||
kpg = KeyPairGenerator.getInstance(algorithm);
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
throw new ServerException(ex.getMessage(), ex);
|
||||
}
|
||||
kpg.initialize(keySize);
|
||||
final KeyPair pair = kpg.generateKeyPair();
|
||||
final SignatureKeyPairImpl kp =
|
||||
new SignatureKeyPairImpl(workspaceId, pair.getPublic(), pair.getPrivate());
|
||||
LOG.debug(
|
||||
"Generated signature key pair with ws id {} and algorithm {}.",
|
||||
kp.getWorkspaceId(),
|
||||
algorithm);
|
||||
return kp;
|
||||
}
|
||||
|
||||
/** Converts {@link SignatureKeyPair} to {@link KeyPair}. */
|
||||
public static KeyPair toJavaKeyPair(SignatureKeyPair keyPair) throws ServerException {
|
||||
try {
|
||||
final PrivateKey privateKey =
|
||||
KeyFactory.getInstance(keyPair.getPrivateKey().getAlgorithm())
|
||||
.generatePrivate(getKeySpec(keyPair.getPrivateKey()));
|
||||
final PublicKey publicKey =
|
||||
KeyFactory.getInstance(keyPair.getPublicKey().getAlgorithm())
|
||||
.generatePublic(getKeySpec(keyPair.getPublicKey()));
|
||||
return new KeyPair(publicKey, privateKey);
|
||||
} catch (NoSuchAlgorithmException | InvalidKeySpecException ex) {
|
||||
LOG.error("Failed to convert signature key pair to Java keys. Cause: {}", ex.getMessage());
|
||||
throw new ServerException("Failed to convert signature key pair to Java keys.");
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns key spec by key format and encoded data. */
|
||||
private static EncodedKeySpec getKeySpec(SignatureKey key) {
|
||||
private EncodedKeySpec getKeySpec(SignatureKey key) {
|
||||
switch (key.getFormat()) {
|
||||
case PKCS_8:
|
||||
return new PKCS8EncodedKeySpec(key.getEncoded());
|
||||
|
|
@ -200,6 +159,21 @@ public class SignatureKeyManager {
|
|||
}
|
||||
}
|
||||
|
||||
private KeyPair toJavaKeyPair(SignatureKeyPair keyPair) throws SignatureKeyManagerException {
|
||||
try {
|
||||
final PrivateKey privateKey =
|
||||
KeyFactory.getInstance(keyPair.getPrivateKey().getAlgorithm())
|
||||
.generatePrivate(getKeySpec(keyPair.getPrivateKey()));
|
||||
final PublicKey publicKey =
|
||||
KeyFactory.getInstance(keyPair.getPublicKey().getAlgorithm())
|
||||
.generatePublic(getKeySpec(keyPair.getPublicKey()));
|
||||
return new KeyPair(publicKey, privateKey);
|
||||
} catch (NoSuchAlgorithmException | InvalidKeySpecException ex) {
|
||||
LOG.error("Failed to convert signature key pair to Java keys. Cause: {}", ex.getMessage());
|
||||
throw new SignatureKeyManagerException("Failed to convert signature key pair to Java keys.");
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@PostConstruct
|
||||
void subscribe() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2018 Red Hat, Inc.
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.multiuser.machine.authentication.server.signature;
|
||||
|
||||
public class SignatureKeyManagerException extends Exception {
|
||||
public SignatureKeyManagerException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public SignatureKeyManagerException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
|
@ -15,7 +15,6 @@ import static org.eclipse.che.multiuser.machine.authentication.shared.Constants.
|
|||
|
||||
import java.util.Base64;
|
||||
import javax.inject.Inject;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
|
||||
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
|
||||
import org.eclipse.che.api.workspace.server.spi.provision.env.EnvVarProvider;
|
||||
|
|
@ -44,10 +43,10 @@ public class SignaturePublicKeyEnvProvider implements EnvVarProvider {
|
|||
Base64.getEncoder()
|
||||
.encode(
|
||||
keyManager
|
||||
.getKeyPair(runtimeIdentity.getWorkspaceId())
|
||||
.getOrCreateKeyPair(runtimeIdentity.getWorkspaceId())
|
||||
.getPublic()
|
||||
.getEncoded())));
|
||||
} catch (ServerException e) {
|
||||
} catch (SignatureKeyManagerException e) {
|
||||
throw new InfrastructureException(
|
||||
"Signature key pair for machine authentication cannot be retrieved. Reason: "
|
||||
+ e.getMessage());
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import org.eclipse.che.api.core.notification.EventService;
|
|||
import org.eclipse.che.api.workspace.server.event.BeforeWorkspaceRemovedEvent;
|
||||
import org.eclipse.che.core.db.cascade.CascadeEventSubscriber;
|
||||
import org.eclipse.che.core.db.jpa.DuplicateKeyException;
|
||||
import org.eclipse.che.core.db.jpa.IntegrityConstraintViolationException;
|
||||
import org.eclipse.che.multiuser.machine.authentication.server.signature.model.impl.SignatureKeyPairImpl;
|
||||
import org.eclipse.che.multiuser.machine.authentication.server.signature.spi.SignatureKeyDao;
|
||||
|
||||
|
|
@ -53,6 +54,12 @@ public class JpaSignatureKeyDao implements SignatureKeyDao {
|
|||
requireNonNull(keyPair, "Required non-null key pair");
|
||||
try {
|
||||
doCreate(keyPair);
|
||||
} catch (IntegrityConstraintViolationException x) {
|
||||
throw new ConflictException(
|
||||
format(
|
||||
"Unable to create signature key pair because referenced workspace with id '%s' doesn't exist",
|
||||
keyPair.getWorkspaceId()));
|
||||
|
||||
} catch (DuplicateKeyException dkEx) {
|
||||
throw new ConflictException(
|
||||
format("Signature key pair for workspace '%s' already exists", keyPair.getWorkspaceId()));
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ public class MachineLoginFilterTest {
|
|||
permissionCheckerMock);
|
||||
|
||||
when(tokenExtractorMock.getToken(any(HttpServletRequest.class))).thenReturn(token);
|
||||
when(keyManagerMock.getKeyPair(eq(WORKSPACE_ID))).thenReturn(keyPair);
|
||||
when(keyManagerMock.getOrCreateKeyPair(eq(WORKSPACE_ID))).thenReturn(keyPair);
|
||||
|
||||
when(userMock.getName()).thenReturn(SUBJECT.getUserName());
|
||||
when(userManagerMock.getById(SUBJECT.getUserId())).thenReturn(userMock);
|
||||
|
|
@ -117,7 +117,7 @@ public class MachineLoginFilterTest {
|
|||
public void testProcessRequestWithValidToken() throws Exception {
|
||||
machineLoginFilter.doFilter(getRequestMock(), responseMock, chainMock);
|
||||
|
||||
verify(keyManagerMock).getKeyPair(eq(WORKSPACE_ID));
|
||||
verify(keyManagerMock).getOrCreateKeyPair(eq(WORKSPACE_ID));
|
||||
verify(userManagerMock).getById(anyString());
|
||||
verifyZeroInteractions(responseMock);
|
||||
}
|
||||
|
|
@ -128,7 +128,7 @@ public class MachineLoginFilterTest {
|
|||
final KeyPairGenerator kpg = KeyPairGenerator.getInstance(SIGNATURE_ALGORITHM);
|
||||
kpg.initialize(KEY_SIZE);
|
||||
final KeyPair pair = kpg.generateKeyPair();
|
||||
when(keyManagerMock.getKeyPair(eq(WORKSPACE_ID))).thenReturn(pair);
|
||||
when(keyManagerMock.getOrCreateKeyPair(eq(WORKSPACE_ID))).thenReturn(pair);
|
||||
|
||||
machineLoginFilter.doFilter(requestMock, responseMock, chainMock);
|
||||
|
||||
|
|
@ -186,7 +186,7 @@ public class MachineLoginFilterTest {
|
|||
|
||||
machineLoginFilter.doFilter(getRequestMock(), responseMock, chainMock);
|
||||
|
||||
verify(keyManagerMock).getKeyPair(eq(WORKSPACE_ID));
|
||||
verify(keyManagerMock).getOrCreateKeyPair(eq(WORKSPACE_ID));
|
||||
verify(userManagerMock).getById(anyString());
|
||||
verify(responseMock)
|
||||
.sendError(
|
||||
|
|
@ -200,7 +200,7 @@ public class MachineLoginFilterTest {
|
|||
|
||||
machineLoginFilter.doFilter(getRequestMock(), responseMock, chainMock);
|
||||
|
||||
verify(keyManagerMock).getKeyPair(eq(WORKSPACE_ID));
|
||||
verify(keyManagerMock).getOrCreateKeyPair(eq(WORKSPACE_ID));
|
||||
verify(userManagerMock).getById(anyString());
|
||||
verify(responseMock)
|
||||
.sendError(
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ import java.util.Map;
|
|||
import org.eclipse.che.api.core.NotFoundException;
|
||||
import org.eclipse.che.api.core.model.user.User;
|
||||
import org.eclipse.che.api.user.server.UserManager;
|
||||
import org.eclipse.che.api.workspace.server.WorkspaceManager;
|
||||
import org.eclipse.che.api.workspace.server.token.MachineTokenException;
|
||||
import org.eclipse.che.commons.subject.SubjectImpl;
|
||||
import org.eclipse.che.multiuser.machine.authentication.server.signature.SignatureKeyManager;
|
||||
import org.mockito.Mock;
|
||||
|
|
@ -58,6 +60,7 @@ public class MachineTokenRegistryTest {
|
|||
|
||||
@Mock private SignatureKeyManager signatureKeyManager;
|
||||
@Mock private UserManager userManager;
|
||||
@Mock private WorkspaceManager workspaceManager;
|
||||
|
||||
private KeyPair keyPair;
|
||||
|
||||
|
|
@ -69,7 +72,7 @@ public class MachineTokenRegistryTest {
|
|||
keyPair = kpg.generateKeyPair();
|
||||
|
||||
mockUser(USER_ID, USER_NAME);
|
||||
when(signatureKeyManager.getKeyPair(anyString())).thenReturn(keyPair);
|
||||
when(signatureKeyManager.getOrCreateKeyPair(anyString())).thenReturn(keyPair);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -89,11 +92,11 @@ public class MachineTokenRegistryTest {
|
|||
assertEquals(subject.getUserName(), USER_NAME);
|
||||
assertEquals(claims.get(WORKSPACE_ID_CLAIM, String.class), WORKSPACE_ID);
|
||||
verify(userManager).getById(USER_ID);
|
||||
verify(signatureKeyManager).getKeyPair(anyString());
|
||||
verify(signatureKeyManager).getOrCreateKeyPair(anyString());
|
||||
assertNotNull(generatedToken);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
@Test(expectedExceptions = MachineTokenException.class)
|
||||
public void testThrowsIllegalStateExceptionWhenTryToGetTokenForNonExistingUser()
|
||||
throws Exception {
|
||||
when(userManager.getById(anyString())).thenThrow(new NotFoundException("User not found"));
|
||||
|
|
|
|||
|
|
@ -11,11 +11,9 @@
|
|||
*/
|
||||
package org.eclipse.che.multiuser.machine.authentication.server.signature;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
|
@ -25,8 +23,6 @@ import static org.testng.Assert.assertNotNull;
|
|||
import java.security.Key;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import org.eclipse.che.api.core.NotFoundException;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.api.core.model.workspace.WorkspaceStatus;
|
||||
import org.eclipse.che.api.core.notification.EventService;
|
||||
import org.eclipse.che.api.core.notification.EventSubscriber;
|
||||
|
|
@ -38,7 +34,6 @@ import org.eclipse.che.multiuser.machine.authentication.server.signature.spi.Sig
|
|||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.mockito.testng.MockitoTestNGListener;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.Listeners;
|
||||
|
|
@ -71,70 +66,6 @@ public class SignatureKeyManagerTest {
|
|||
new SignatureKeyManager(KEY_SIZE, ALGORITHM, eventService, signatureKeyDao);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadSignatureKeys() throws Exception {
|
||||
String wsId = "WS_id_1";
|
||||
final SignatureKeyPairImpl kp = newKeyPair(wsId);
|
||||
when(signatureKeyDao.get(anyString())).thenReturn(kp);
|
||||
|
||||
signatureKeyManager.loadKeyPair(wsId);
|
||||
|
||||
final KeyPair cachedPair = signatureKeyManager.getKeyPair(wsId);
|
||||
assertNotNull(cachedPair);
|
||||
assertKeys(cachedPair.getPublic(), kp.getPublicKey());
|
||||
assertKeys(cachedPair.getPrivate(), kp.getPrivateKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTriesToLoadKeysOnGettingKeyPairAndNoCachedKeyPair() throws Exception {
|
||||
String wsId = "WS_id_1";
|
||||
final SignatureKeyPairImpl kp = newKeyPair(wsId);
|
||||
when(signatureKeyDao.create(any(SignatureKeyPairImpl.class))).thenReturn(kp);
|
||||
when(signatureKeyDao.get(anyString())).thenThrow(new NotFoundException("not found"));
|
||||
|
||||
signatureKeyManager.getKeyPair("ws1");
|
||||
|
||||
verify(signatureKeyDao).get(anyString());
|
||||
verify(signatureKeyDao).create(any(SignatureKeyPairImpl.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGeneratesNewKeyPairWhenNoExistingKeyPairFound() throws Exception {
|
||||
doThrow(NotFoundException.class).when(signatureKeyDao).get(anyString());
|
||||
when(signatureKeyDao.create(any(SignatureKeyPairImpl.class)))
|
||||
.thenAnswer((Answer<SignatureKeyPairImpl>) invoke -> invoke.getArgument(0));
|
||||
|
||||
final KeyPair cachedPair = signatureKeyManager.getKeyPair("ws1");
|
||||
|
||||
verify(signatureKeyDao).get(anyString());
|
||||
verify(signatureKeyDao).create(any(SignatureKeyPairImpl.class));
|
||||
assertNotNull(cachedPair);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = ServerException.class)
|
||||
public void testThrowsExceptionWhenFailedToLoadAndGenerateKeys() throws Exception {
|
||||
doThrow(NotFoundException.class).when(signatureKeyDao).get(anyString());
|
||||
when(signatureKeyDao.create(any(SignatureKeyPairImpl.class)))
|
||||
.thenThrow(new ServerException("unexpected end of stack"));
|
||||
|
||||
signatureKeyManager.getKeyPair("ws1");
|
||||
|
||||
verify(signatureKeyDao).get(anyString());
|
||||
verify(signatureKeyDao).create(any(SignatureKeyPairImpl.class));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = ServerException.class)
|
||||
public void testThrowsExceptionWhenAlgorithmIsNotSupported() throws Exception {
|
||||
final SignatureKeyImpl publicKey = new SignatureKeyImpl(new byte[] {}, "ECDH", "PKCS#15");
|
||||
final SignatureKeyImpl privateKey = new SignatureKeyImpl(new byte[] {}, "ECDH", "PKCS#3");
|
||||
final SignatureKeyPairImpl kp = new SignatureKeyPairImpl("id_" + 1, publicKey, privateKey);
|
||||
doReturn(kp).when(signatureKeyDao).get(anyString());
|
||||
|
||||
signatureKeyManager.getKeyPair("ws1");
|
||||
|
||||
verify(signatureKeyDao).get(anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldRemoveKeyPairOnWorkspaceStop() throws Exception {
|
||||
final String wsId = "ws123";
|
||||
|
|
@ -150,6 +81,31 @@ public class SignatureKeyManagerTest {
|
|||
verify(signatureKeyDao, times(1)).remove(eq(wsId));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = SignatureKeyManagerException.class)
|
||||
public void shouldThrowsExceptionWhenAlgorithmIsNotSupported() throws Exception {
|
||||
final SignatureKeyImpl publicKey = new SignatureKeyImpl(new byte[] {}, "ECDH", "PKCS#15");
|
||||
final SignatureKeyImpl privateKey = new SignatureKeyImpl(new byte[] {}, "ECDH", "PKCS#3");
|
||||
final SignatureKeyPairImpl kp = new SignatureKeyPairImpl("id_" + 1, publicKey, privateKey);
|
||||
doReturn(kp).when(signatureKeyDao).get(anyString());
|
||||
|
||||
signatureKeyManager.getOrCreateKeyPair("ws1");
|
||||
|
||||
verify(signatureKeyDao).get(anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnSignatureKeys() throws Exception {
|
||||
String wsId = "WS_id_1";
|
||||
final SignatureKeyPairImpl kp = newKeyPair(wsId);
|
||||
when(signatureKeyDao.get(anyString())).thenReturn(kp);
|
||||
|
||||
final KeyPair cachedPair = signatureKeyManager.getOrCreateKeyPair(wsId);
|
||||
|
||||
assertNotNull(cachedPair);
|
||||
assertKeys(cachedPair.getPublic(), kp.getPublicKey());
|
||||
assertKeys(cachedPair.getPrivate(), kp.getPrivateKey());
|
||||
}
|
||||
|
||||
private SignatureKeyPairImpl newKeyPair(String id) {
|
||||
final KeyPair pair = kpg.generateKeyPair();
|
||||
return new SignatureKeyPairImpl(id, pair.getPublic(), pair.getPrivate());
|
||||
|
|
|
|||
|
|
@ -121,6 +121,15 @@ public class SignatureKeyDaoTest {
|
|||
dao.create(signKeyPair);
|
||||
}
|
||||
|
||||
@Test(
|
||||
expectedExceptions = ConflictException.class,
|
||||
expectedExceptionsMessageRegExp =
|
||||
"Unable to create signature key pair because referenced workspace with id '.*' doesn't exist")
|
||||
public void throwsConflictExceptionWhenCreatingKeyPairNotExistedWs() throws Exception {
|
||||
|
||||
dao.create(newKeyPair("wrong_ws"));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NotFoundException.class)
|
||||
public void throwsNoResultExceptionWhenSearchingWrongWorkspace() throws Exception {
|
||||
dao.get("unknown");
|
||||
|
|
|
|||
Loading…
Reference in New Issue