Skip to content
Permalink
Browse files
Finding ways to sign the application refresh token.
  • Loading branch information
mifosio-04-04-2018 committed Apr 28, 2017
1 parent 2f58169 commit 844021e23ba442a87d41fb77c1fc80da49668501
Showing 7 changed files with 158 additions and 48 deletions.
@@ -53,7 +53,7 @@ public ResponseEntity<Void> initialize()

final ApplicationSignatureSet applicationSignatureSet = new ApplicationSignatureSet(identityManagerKeyPair.getTimestamp(), applicationSignature, identityManagerSignature);

this.specialTenantSignatureRepository.addSignatureSet(applicationSignatureSet);
this.specialTenantSignatureRepository.addSignatureSet(applicationSignatureSet, applicationKeyPair);
initialized = true;
return new ResponseEntity<>(HttpStatus.OK);
}
@@ -18,6 +18,7 @@
import io.mifos.anubis.api.v1.domain.ApplicationSignatureSet;
import io.mifos.anubis.api.v1.domain.Signature;
import io.mifos.anubis.config.TenantSignatureRepository;
import io.mifos.core.lang.security.RsaKeyPairFactory;
import org.springframework.stereotype.Component;

import java.util.HashMap;
@@ -31,15 +32,38 @@
*/
@Component
public class SpecialTenantSignatureRepository implements TenantSignatureRepository {
private final Map<String, ApplicationSignatureSet> applicationSignatureSetMap = new HashMap<>();
private static class AllTheKeyInfos {
final ApplicationSignatureSet applicationSignatureSet;
final RsaKeyPairFactory.KeyPairHolder applicationKeyPair;

void addSignatureSet(final ApplicationSignatureSet applicationSignatureSet) {
applicationSignatureSetMap.put(applicationSignatureSet.getTimestamp(), applicationSignatureSet);
private AllTheKeyInfos(
final ApplicationSignatureSet applicationSignatureSet,
final RsaKeyPairFactory.KeyPairHolder applicationKeyPair) {
this.applicationSignatureSet = applicationSignatureSet;
this.applicationKeyPair = applicationKeyPair;
}

ApplicationSignatureSet getApplicationSignatureSet() {
return applicationSignatureSet;
}

RsaKeyPairFactory.KeyPairHolder getApplicationKeyPair() {
return applicationKeyPair;
}
}
private final Map<String, AllTheKeyInfos> applicationSignatureSetMap = new HashMap<>();

void addSignatureSet(final ApplicationSignatureSet applicationSignatureSet,
final RsaKeyPairFactory.KeyPairHolder applicationKeyPair) {
applicationSignatureSetMap.put(applicationSignatureSet.getTimestamp(),
new AllTheKeyInfos(applicationSignatureSet, applicationKeyPair));
}

@Override
public Optional<Signature> getIdentityManagerSignature(final String timestamp) throws IllegalArgumentException {
final Optional<ApplicationSignatureSet> sigset = Optional.ofNullable(applicationSignatureSetMap.get(timestamp));
final Optional<ApplicationSignatureSet> sigset =
Optional.ofNullable(applicationSignatureSetMap.get(timestamp))
.map(AllTheKeyInfos::getApplicationSignatureSet);
return sigset.map(ApplicationSignatureSet::getIdentityManagerSignature);
}

@@ -50,7 +74,8 @@ public List<String> getAllSignatureSetKeyTimestamps() {

@Override
public Optional<ApplicationSignatureSet> getSignatureSet(final String timestamp) {
return Optional.ofNullable(applicationSignatureSetMap.get(timestamp));
return Optional.ofNullable(applicationSignatureSetMap.get(timestamp))
.map(AllTheKeyInfos::getApplicationSignatureSet);
}

@Override
@@ -60,24 +85,34 @@ public void deleteSignatureSet(final String timestamp) {

@Override
public Optional<Signature> getApplicationSignature(final String timestamp) {
final Optional<ApplicationSignatureSet> sigset = Optional.ofNullable(applicationSignatureSetMap.get(timestamp));
final Optional<ApplicationSignatureSet> sigset
= Optional.ofNullable(applicationSignatureSetMap.get(timestamp))
.map(AllTheKeyInfos::getApplicationSignatureSet);
return sigset.map(ApplicationSignatureSet::getApplicationSignature);
}

@Override
public Optional<ApplicationSignatureSet> getLatestSignatureSet() {
Optional<String> timestamp = getMostRecentTimestamp();
final Optional<String> timestamp = getMostRecentTimestamp();
return timestamp.flatMap(this::getSignatureSet);
}

@Override
public Optional<Signature> getLatestApplicationSignature() {
Optional<String> timestamp = getMostRecentTimestamp();
final Optional<String> timestamp = getMostRecentTimestamp();
return timestamp.flatMap(this::getApplicationSignature);
}

@Override
public Optional<RsaKeyPairFactory.KeyPairHolder> getLatestApplicationSigningKeyPair() {
final Optional<String> timestamp = getMostRecentTimestamp();
return timestamp
.flatMap(x -> Optional.ofNullable(applicationSignatureSetMap.get(x)))
.map(AllTheKeyInfos::getApplicationKeyPair);
}

private Optional<String> getMostRecentTimestamp() {
return getAllSignatureSetKeyTimestamps().stream()
.max(String::compareTo);
}
}
}
@@ -18,7 +18,9 @@

import io.mifos.anubis.api.v1.domain.ApplicationSignatureSet;
import io.mifos.anubis.api.v1.domain.Signature;
import io.mifos.core.lang.security.RsaKeyPairFactory;

import java.security.interfaces.RSAPrivateKey;
import java.util.List;
import java.util.Optional;

@@ -42,4 +44,6 @@ public interface TenantSignatureRepository {
Optional<Signature> getApplicationSignature(String timestamp);

Optional<Signature> getLatestApplicationSignature();

Optional<RsaKeyPairFactory.KeyPairHolder> getLatestApplicationSigningKeyPair();
}
@@ -27,6 +27,8 @@
import io.mifos.core.cassandra.core.CassandraSessionProvider;
import io.mifos.core.lang.ApplicationName;
import io.mifos.core.lang.security.RsaKeyPairFactory;
import io.mifos.core.lang.security.RsaPrivateKeyBuilder;
import io.mifos.core.lang.security.RsaPublicKeyBuilder;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
@@ -35,6 +37,10 @@

import javax.annotation.Nonnull;
import java.math.BigInteger;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -283,6 +289,24 @@ private static Signature mapRowToApplicationSignature(final @Nonnull Row row) {
return getSignature(row, APPLICATION_PUBLIC_KEY_MOD_COLUMN, APPLICATION_PUBLIC_KEY_EXP_COLUMN);
}

private static RsaKeyPairFactory.KeyPairHolder mapRowToKeyPairHolder(final @Nonnull Row row) {
final BigInteger publicKeyModulus = row.get(APPLICATION_PUBLIC_KEY_MOD_COLUMN, BigInteger.class);
final BigInteger publicKeyExponent = row.get(APPLICATION_PUBLIC_KEY_EXP_COLUMN, BigInteger.class);
final BigInteger privateKeyModulus = row.get(APPLICATION_PRIVATE_KEY_MOD_COLUMN, BigInteger.class);
final BigInteger privateKeyExponent = row.get(APPLICATION_PRIVATE_KEY_EXP_COLUMN, BigInteger.class);

final PublicKey publicKey = new RsaPublicKeyBuilder()
.setPublicKeyMod(publicKeyModulus)
.setPublicKeyExp(publicKeyExponent)
.build();
final PrivateKey privateKey = new RsaPrivateKeyBuilder()
.setPrivateKeyMod(privateKeyModulus)
.setPrivateKeyExp(privateKeyExponent)
.build();
final String timestamp = row.get(TIMESTAMP_COLUMN, String.class);
return new RsaKeyPairFactory.KeyPairHolder(timestamp, (RSAPublicKey)publicKey, (RSAPrivateKey)privateKey);
}

private static ApplicationSignatureSet mapRowToSignatureSet(final @Nonnull Row row) {
final String timestamp = row.get(TIMESTAMP_COLUMN, String.class);
final Signature identityManagerSignature = mapRowToIdentityManagerSignature(row);
@@ -316,6 +340,12 @@ public Optional<Signature> getLatestApplicationSignature() {
return timestamp.flatMap(this::getApplicationSignature);
}

@Override
public Optional<RsaKeyPairFactory.KeyPairHolder> getLatestApplicationSigningKeyPair() {
Optional<String> timestamp = getMostRecentTimestamp();
return timestamp.flatMap(this::getRow).map(TenantAuthorizationDataRepository::mapRowToKeyPairHolder);
}

private Optional<String> getMostRecentTimestamp() {
return getAllSignatureSetKeyTimestamps().stream()
.max(String::compareTo);
@@ -0,0 +1,28 @@
/*
* 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.token;

import io.mifos.anubis.provider.InvalidKeyTimestampException;

import java.security.PublicKey;

/**
* @author Myrle Krantz
*/
@SuppressWarnings("WeakerAccess")
public interface TenantApplicationRsaKeyProvider {
PublicKey getApplicationPublicKey(String issuingApplication, String timestamp) throws InvalidKeyTimestampException;
}
@@ -18,9 +18,7 @@
import io.jsonwebtoken.*;
import io.mifos.anubis.api.v1.TokenConstants;
import io.mifos.anubis.provider.InvalidKeyTimestampException;
import io.mifos.anubis.provider.TenantRsaKeyProvider;
import io.mifos.anubis.security.AmitAuthenticationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Nonnull;
@@ -36,15 +34,6 @@
@SuppressWarnings("WeakerAccess")
@Component
public class TenantRefreshTokenSerializer {

final private TenantRsaKeyProvider tenantRsaKeyProvider;

@SuppressWarnings("SpringJavaAutowiringInspection")
@Autowired
TenantRefreshTokenSerializer(final TenantRsaKeyProvider tenantRsaKeyProvider) {
this.tenantRsaKeyProvider = tenantRsaKeyProvider;
}

@SuppressWarnings("WeakerAccess")
public static class Specification {
private String keyTimestamp;
@@ -110,7 +99,7 @@ public TokenSerializationResult build(final Specification specification)
return new TokenSerializationResult(TokenConstants.PREFIX + jwtBuilder.compact(), expiration);
}

public TokenDeserializationResult deserialize(final String refreshToken)
public TokenDeserializationResult deserialize(final TenantApplicationRsaKeyProvider tenantRsaKeyProvider, final String refreshToken)
{
final Optional<String> tokenString = getJwtTokenString(refreshToken);

@@ -121,9 +110,10 @@ public TokenDeserializationResult deserialize(final String refreshToken)
final JwtParser parser = Jwts.parser().setSigningKeyResolver(new SigningKeyResolver() {
@Override public Key resolveSigningKey(final JwsHeader header, final Claims claims) {
final String keyTimestamp = getKeyTimestampFromClaims(claims);
final String issuingApplication = getIssuingApplicationFromClaims(claims);

try {
return tenantRsaKeyProvider.getPublicKey(keyTimestamp);
return tenantRsaKeyProvider.getApplicationPublicKey(issuingApplication, keyTimestamp);
}
catch (final IllegalArgumentException e)
{
@@ -165,4 +155,9 @@ private static Optional<String> getJwtTokenString(final String refreshToken) {
String getKeyTimestampFromClaims(final Claims claims) {
return claims.get(TokenConstants.JWT_SIGNATURE_TIMESTAMP_CLAIM, String.class);
}

private @Nonnull
String getIssuingApplicationFromClaims(final Claims claims) {
return claims.getIssuer();
}
}

0 comments on commit 844021e

Please sign in to comment.