blob: d81a210cd02e8d2605209d3e1ea003fcc1b9a783 [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.
*/
import io.mifos.anubis.api.v1.RoleConstants;
import io.mifos.anubis.api.v1.domain.ApplicationSignatureSet;
import io.mifos.anubis.api.v1.domain.Signature;
import io.mifos.anubis.test.v1.TenantApplicationSecurityEnvironmentTestRule;
import io.mifos.anubis.token.SystemAccessTokenSerializer;
import io.mifos.core.api.config.EnableApiFactory;
import io.mifos.core.api.context.AutoSeshat;
import io.mifos.core.api.context.AutoUserContext;
import io.mifos.core.api.util.ApiFactory;
import io.mifos.core.api.util.InvalidTokenException;
import io.mifos.core.lang.TenantContextHolder;
import io.mifos.core.test.env.TestEnvironment;
import io.mifos.core.test.fixture.TenantDataStoreTestContext;
import io.mifos.core.test.fixture.cassandra.CassandraInitializer;
import io.mifos.identity.api.v1.client.IdentityManager;
import io.mifos.identity.api.v1.client.TenantAlreadyInitializedException;
import io.mifos.identity.config.IdentityServiceConfig;
import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.junit4.SpringRunner;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPrivateKeySpec;
import java.util.concurrent.TimeUnit;
/**
* @author Myrle Krantz
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class TestProvisioning {
private static final String APP_NAME = "identity-v1";
@Configuration
@EnableApiFactory
@Import({IdentityServiceConfig.class})
public static class TestConfiguration {
public TestConfiguration() {
super();
}
@Bean()
public Logger logger() {
return LoggerFactory.getLogger("login-test-logger");
}
}
private static final String ADMIN_PASSWORD = "golden_osiris";
private final static TestEnvironment testEnvironment = new TestEnvironment(APP_NAME);
private final static CassandraInitializer cassandraInitializer = new CassandraInitializer();
//Not using this as a rule because initialize in idnetity manager is different.
private static final TenantApplicationSecurityEnvironmentTestRule tenantApplicationSecurityEnvironment = new TenantApplicationSecurityEnvironmentTestRule(testEnvironment);
@ClassRule
public static TestRule orderClassRules = RuleChain
.outerRule(testEnvironment)
.around(cassandraInitializer);
@SuppressWarnings("SpringAutowiredFieldsWarningInspection")
@Autowired ApiFactory apiFactory;
@Test
public void testBoundaryInitializeCases() throws InterruptedException {
final IdentityManager testSubject = getTestSubject();
final ApplicationSignatureSet firstTenantSignatureSet;
Signature firstTenantIdentityManagerSignature = null;
try (final TenantDataStoreTestContext ignored = TenantDataStoreTestContext.forRandomTenantName(cassandraInitializer)) {
final String invalidSeshatToken = "notBearer";
try (final AutoSeshat ignored2 = new AutoSeshat(invalidSeshatToken)){
testSubject.initialize(Helpers.encodePassword(ADMIN_PASSWORD));
Assert.fail("The key had the wrong format. This should've failed.");
}
catch (final InvalidTokenException ignored2)
{
}
final String wrongSystemToken = systemTokenFromWrongKey();
try (final AutoSeshat ignored2 = new AutoSeshat(wrongSystemToken)){
testSubject.initialize(Helpers.encodePassword(ADMIN_PASSWORD));
Assert.fail("The key was signed by the wrong source. This should've failed.");
}
catch (final Exception e)
{
Assert.assertTrue("The exception should be 'invalid token'", (e instanceof InvalidTokenException));
}
try (final AutoUserContext ignored2 = tenantApplicationSecurityEnvironment.createAutoSeshatContext("goober")) {
testSubject.initialize(Helpers.encodePassword(ADMIN_PASSWORD));
Assert.fail("The key was intended for a different tenant. This should've failed.");
}
catch (final Exception e)
{
Assert.assertTrue("The exception should be 'not found'", (e instanceof InvalidTokenException));
}
try (final AutoUserContext ignored2 = tenantApplicationSecurityEnvironment.createAutoSeshatContext()) {
firstTenantSignatureSet = testSubject.initialize(Helpers.encodePassword(ADMIN_PASSWORD));
final Signature applicationSignature = tenantApplicationSecurityEnvironment.getAnubis().getApplicationSignature(firstTenantSignatureSet.getTimestamp());
firstTenantIdentityManagerSignature = tenantApplicationSecurityEnvironment.getAnubis().getSignatureSet(firstTenantSignatureSet.getTimestamp()).getIdentityManagerSignature();
Assert.assertEquals(applicationSignature, firstTenantIdentityManagerSignature);
testSubject.initialize("golden_osiris");
Assert.fail("The second otherwise valid call to initialize for the same tenant should "
+ "fail because the tenant is now already initialized.");
}
catch (final TenantAlreadyInitializedException e)
{
//All is well.
}
}
final ApplicationSignatureSet secondTenantSignatureSet;
try (final TenantDataStoreTestContext ignored = TenantDataStoreTestContext.forRandomTenantName(cassandraInitializer)) {
try (final AutoUserContext ignored2
= tenantApplicationSecurityEnvironment.createAutoSeshatContext()) {
secondTenantSignatureSet = testSubject.initialize(Helpers.encodePassword(ADMIN_PASSWORD));
final Signature secondTenantIdentityManagerSignature = tenantApplicationSecurityEnvironment.getAnubis().getApplicationSignature(secondTenantSignatureSet.getTimestamp());
Assert.assertNotEquals(firstTenantIdentityManagerSignature, secondTenantIdentityManagerSignature);
}
}
catch (final Exception e)
{
Assert.fail("Call to initialize for a second tenant should succeed. "
+ "The exception was " + e
);
throw e;
}
TenantContextHolder.clear();
}
private IdentityManager getTestSubject() {
return apiFactory.create(IdentityManager.class, testEnvironment.serverURI());
}
private String systemTokenFromWrongKey()
{
final SystemAccessTokenSerializer.Specification tokenSpecification
= new SystemAccessTokenSerializer.Specification();
tokenSpecification.setKeyTimestamp("rando");
tokenSpecification.setPrivateKey(getWrongPrivateKey());
tokenSpecification.setRole(RoleConstants.SYSTEM_ADMIN_ROLE_IDENTIFIER);
tokenSpecification.setSecondsToLive(TimeUnit.HOURS.toSeconds(12L));
tokenSpecification.setTargetApplicationName(APP_NAME);
tokenSpecification.setTenant(TenantContextHolder.checkedGetIdentifier());
return new SystemAccessTokenSerializer().build(tokenSpecification).getToken();
}
private PrivateKey getWrongPrivateKey() {
try {
final KeyFactory keyFactory = KeyFactory.getInstance("RSA");
final BigInteger privateKeyMod = new BigInteger("17492023076590407419772677529630320569634203626210733433914657600705550392421401008213478702016995697617177968917710500448063776244435761300358170637857566629780506514059676334317863416316403254208652514809444684705031748559737773841335114470369449872988726825545007588731959817361831095583721775522968972071928027030514641182819255368960492742269021132488312466659639538013906582095129294788911611410130509557024329936361580892139238423117992298190557606490543083859770282260174239092737213765902825945545746379786237952115129023474946280230282545899883335448866567923667432417504919606306921621754480829178419392063");
final BigInteger privateKeyExp = new BigInteger("3836197074627064495542864246660307880240969356539464297200899853440665208817504565223497099105700278649491111086168927826113808321425686210385705579717210204462139251515628239821027066889171978771395739740240603830895850009141569242130546108040040023566336125601696661013541334741315567340965150672011734372736240827969821590544366269533567400051316301569296349329670063250330460924547069022975441956699127698164632663315582302411984903513839691646332895582584509587803859003388718326640891827257180737700763719907116123118603418352134643169731657061459925351503055596019271348089711003706283690698717182672701958953");
final RSAPrivateKeySpec privateKeySpec = new RSAPrivateKeySpec(privateKeyMod, privateKeyExp);
return keyFactory.generatePrivate(privateKeySpec);
} catch (final InvalidKeySpecException | NoSuchAlgorithmException e) {
throw new IllegalStateException(e);
}
}
}