blob: faed3731e227b52c09d32477f9f626035faf1709 [file] [log] [blame]
/*
* Copyright 2017 The Mifos Initiative.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.mifos.anubis.test.v1;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.jsonwebtoken.*;
import io.mifos.anubis.annotation.AcceptedTokenType;
import io.mifos.anubis.api.v1.RoleConstants;
import io.mifos.anubis.api.v1.TokenConstants;
import io.mifos.anubis.api.v1.domain.AllowedOperation;
import io.mifos.anubis.api.v1.domain.TokenContent;
import io.mifos.anubis.api.v1.domain.TokenPermission;
import io.mifos.anubis.provider.InvalidKeyTimestampException;
import io.mifos.anubis.provider.SystemRsaKeyProvider;
import io.mifos.anubis.security.SystemAuthenticator;
import io.mifos.anubis.service.PermittableService;
import io.mifos.anubis.token.SystemAccessTokenSerializer;
import io.mifos.anubis.token.TenantAccessTokenSerializer;
import io.mifos.core.api.context.AutoSeshat;
import io.mifos.core.api.context.AutoUserContext;
import io.mifos.core.api.util.ApiConstants;
import io.mifos.core.api.util.UserContextHolder;
import io.mifos.core.lang.TenantContextHolder;
import io.mifos.core.lang.security.RsaKeyPairFactory;
import org.mockito.Mockito;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* @author Myrle Krantz
*/
@SuppressWarnings({"WeakerAccess", "unused"})
public class SystemSecurityEnvironment {
final static String LOGGER_NAME = "anubis-test-logger";
private final TenantAccessTokenSerializer tenantAccessTokenSerializer;
private final SystemAccessTokenSerializer systemAccessTokenSerializer;
private final String systemKeyTimestamp;
private final PublicKey systemPublicKey;
private final PrivateKey systemPrivateKey;
private final Map<String, RsaKeyPairFactory.KeyPairHolder> tenantKeyPairHolders;
public SystemSecurityEnvironment(final String systemKeyTimestamp, final PublicKey systemPublicKey, final PrivateKey systemPrivateKey) {
final Gson gson = new GsonBuilder().create();
this.tenantAccessTokenSerializer = new TenantAccessTokenSerializer(gson);
this.systemAccessTokenSerializer = new SystemAccessTokenSerializer();
this.systemKeyTimestamp = systemKeyTimestamp;
this.systemPublicKey = systemPublicKey;
this.systemPrivateKey = systemPrivateKey;
this.tenantKeyPairHolders = new HashMap<>();
}
public AutoUserContext createAutoSystemContext(final String applicationName)
{
return new AutoSeshat(systemToken(applicationName));
}
public AutoUserContext createAutoSystemContext(final String tenantName, final String applicationName) {
return new AutoSeshat(systemToken(tenantName, applicationName));
}
public String systemToken(final String applicationName) {
return systemToken(TenantContextHolder.checkedGetIdentifier(), applicationName);
}
private String systemToken(final String tenantName, final String applicationName) {
return systemAccessTokenSerializer.build(new SystemAccessTokenSerializer.Specification()
.setTenant(tenantName)
.setRole(RoleConstants.SYSTEM_ADMIN_ROLE_IDENTIFIER)
.setSecondsToLive(TimeUnit.HOURS.toSeconds(12))
.setKeyTimestamp(systemKeyTimestamp)
.setPrivateKey(systemPrivateKey)
.setTargetApplicationName(applicationName)
).getToken();
}
public AutoUserContext createAutoUserContext(final String userName, final List<String> applicationNames)
{
return new AutoUserContext(userName, getEverythingToken(userName, applicationNames));
}
private String getEverythingToken(final String userName, final List<String> applicationNames)
{
return tenantAccessTokenSerializer.build(new TenantAccessTokenSerializer.Specification()
.setUser(userName)
.setTokenContent(getTokenContentForStarEndpoint(applicationNames))
.setSecondsToLive(TimeUnit.HOURS.toSeconds(10))
.setKeyTimestamp(tenantKeyTimestamp())
.setPrivateKey(tenantPrivateKey())).getToken();
}
public String getPermissionToken(
final String userName,
final String applicationName,
final String uri,
final AllowedOperation allowedOperation) {
return tenantAccessTokenSerializer.build(
new TenantAccessTokenSerializer.Specification().setPrivateKey(tenantPrivateKey())
.setKeyTimestamp(tenantKeyTimestamp())
.setSecondsToLive(100)
.setUser(userName)
.setTokenContent(generateOnePermissionTokenContent(applicationName, uri, allowedOperation))
).getToken();
}
private TokenContent generateOnePermissionTokenContent(final String applicationName, final String uri, final AllowedOperation allowedOperation) {
final TokenPermission tokenPermission
= new TokenPermission(applicationName + uri, Collections.singleton(allowedOperation));
return new TokenContent(Collections.singletonList(tokenPermission));
}
public String tenantKeyTimestamp() {
return tenantKeyPairHolders.computeIfAbsent(TenantContextHolder.checkedGetIdentifier(),
x -> RsaKeyPairFactory.createKeyPair()).getTimestamp();
}
public RSAPublicKey tenantPublicKey()
{
return tenantKeyPairHolders.computeIfAbsent(TenantContextHolder.checkedGetIdentifier(),
x -> RsaKeyPairFactory.createKeyPair()).publicKey();
}
public RSAPrivateKey tenantPrivateKey()
{
return tenantKeyPairHolders.computeIfAbsent(TenantContextHolder.checkedGetIdentifier(),
x -> RsaKeyPairFactory.createKeyPair()).privateKey();
}
private TokenContent getTokenContentForStarEndpoint(final List<String> applicationNames) {
return new TokenContent(
applicationNames.stream()
.map(x -> new TokenPermission(x + "/*", AllowedOperation.ALL))
.collect(Collectors.toList()));
}
public boolean isValidGuestSecurityContext(final String forTenant) {
final boolean validTenant = TenantContextHolder.identifier().map(x -> x.equals(forTenant)).orElse(false);
final boolean validUser = UserContextHolder.checkedGetUser().equals(RoleConstants.GUEST_USER_IDENTIFIER);
final boolean validToken = UserContextHolder.checkedGetAccessToken().equals(TokenConstants.NO_AUTHENTICATION);
return validTenant && validUser && validToken;
}
public boolean isValidSystemSecurityContext(final String forService, final String forServiceVersion, final String forTenant) {
final boolean validTenant = TenantContextHolder.identifier().map(x -> x.equals(forTenant)).orElse(false);
final boolean validUser = UserContextHolder.checkedGetUser().equals(ApiConstants.SYSTEM_SU);
final boolean validToken = isValidToken(
UserContextHolder.checkedGetAccessToken(),
forService,
forServiceVersion,
UserContextHolder.checkedGetUser());
return validTenant && validUser && validToken;
}
public boolean isValidToken(final String token,
final String forService,
final String forServiceVersion,
final String forUser) {
if (!token.startsWith(TokenConstants.PREFIX))
return false;
final String jwtToken = token.substring(TokenConstants.PREFIX.length()).trim();
final PermittableService permittableService = Mockito.mock(PermittableService.class);
Mockito.doReturn(Collections.emptySet()).when(permittableService).getPermittableEndpointsAsPermissions(AcceptedTokenType.SYSTEM);
final SystemRsaKeyProvider systemRsaKeyProvider = Mockito.mock(SystemRsaKeyProvider.class);
try {
Mockito.doReturn(systemPublicKey).when(systemRsaKeyProvider).getPublicKey(Mockito.anyString());
}
catch (final InvalidKeyTimestampException ignored) {}
final Logger logger = LoggerFactory.getLogger(LOGGER_NAME);
final SystemAuthenticator systemAuthenticator = new SystemAuthenticator(
systemRsaKeyProvider,
permittableService,
logger);
try {
return (systemAuthenticator.authenticate(forUser, jwtToken, systemKeyTimestamp) != null);
}
catch (final Exception e)
{
return false;
}
}
public static TokenContent getTokenContent(final String token, final PublicKey publicKey)
{
final String strippedAccessToken = token.substring("Bearer ".length());
final JwtParser parser = Jwts.parser().setSigningKey(publicKey);
@SuppressWarnings("unchecked") final Jwt<Header, Claims> jwt = parser.parse(strippedAccessToken);
final String serializedTokenContent = jwt.getBody().get(TokenConstants.JWT_CONTENT_CLAIM, String.class);
return new Gson().fromJson(serializedTokenContent, TokenContent.class);
}
}