package io.fathom.cloud.identity.secrets; import io.fathom.cloud.CloudException; import io.fathom.cloud.PasswordHasher; import io.fathom.cloud.identity.secrets.SecretToken.SecretTokenType; import io.fathom.cloud.identity.state.AuthRepository; import io.fathom.cloud.protobuf.IdentityModel.CredentialData; import io.fathom.cloud.protobuf.IdentityModel.SecretKeyData; import io.fathom.cloud.protobuf.IdentityModel.SecretKeyType; import io.fathom.cloud.protobuf.IdentityModel.SecretStoreData; import io.fathom.cloud.protobuf.IdentityModel.UserData; import io.fathom.cloud.protobuf.IdentityModel.UserSecretData; import javax.inject.Inject; import javax.inject.Singleton; import org.keyczar.DefaultKeyType; import org.keyczar.KeyMetadata; import org.keyczar.KeyczarKey; import org.keyczar.KeyczarUtils; import org.keyczar.enums.KeyPurpose; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Strings; import com.google.inject.persist.Transactional; @Singleton @Transactional public class Migrations { private static final Logger log = LoggerFactory.getLogger(Migrations.class); public static void report(Object o) { log.warn("Temporary migration for: {}", o); } @Inject AuthRepository authRepository; @Inject @Deprecated PasswordHasher hasher; @Inject Secrets secretService; public UserWithSecret migrateUserAddPasswordRecovery(UserWithSecret user, SecretToken secretToken) throws CloudException { UserSecretData userSecretData = user.userSecretData; UserData userData = user.getUserData(); for (SecretKeyData entry : userData.getSecretStore().getSecretKeyList()) { if (entry.getType() == SecretKeyType.ENCRYPTED_WITH_FORGOTPASSWORD_PUBKEY) { return user; } } log.info("Migrating user - adding password recovery: {}", user.getUserData()); report(userData); UserData.Builder userDataBuilder = UserData.newBuilder(userData); UserSecretData.Builder userSecretDataBuilder = UserSecretData.newBuilder(userSecretData); secretService.addTokenRecovery(userDataBuilder, secretToken); userData = authRepository.getUsers().update(userDataBuilder); return new UserWithSecret(userData, userSecretData, secretToken); } public UserData migrateUser(CredentialData credential, UserData user, String password) throws CloudException { if (!user.hasSecretStore()) { if (hasher.isValid(credential.getDeprecatedPasswordHash(), password)) { log.warn("Migrating user password to new secure store"); SecretToken userSecret = SecretToken.create(SecretTokenType.USER_SECRET); UserData.Builder b = UserData.newBuilder(user); SecretStoreData.Builder secretStore = b.getSecretStoreBuilder(); if (!Strings.isNullOrEmpty(password)) { Secrets.setPassword(secretStore, password, userSecret); } else { // Without a password, there's going to be no way to get the // key throw new UnsupportedOperationException(); } // KeyPair keypair = KeyPairs.generateKeyPair(); // byte[] publicKey = keypair.getPublic().getEncoded(); // byte[] privateKey = keypair.getPrivate().getEncoded(); // // b.getPublicKeyBuilder().setEncoded(ByteString.copyFrom(publicKey)); if (b.hasSecretData()) { throw new IllegalStateException(); } UserSecretData.Builder s = UserSecretData.newBuilder(); // // s.setVerifyUserId(b.getId()); // s.getPrivateKeyBuilder().setEncoded(ByteString.copyFrom(privateKey)); // b.setSecretData(Secrets.buildUserSecret(userSecret, s.build())); user = authRepository.getUsers().update(b); } } return user; } public UserWithSecret migrateUser(UserWithSecret user, String password, SecretToken secretToken) throws CloudException { UserSecretData userSecretData = user.userSecretData; UserData userData = user.getUserData(); if (!userData.getPublicKey().hasKeyczar()) { log.info("Migrating user to keyczar: {}", user.getUserData()); Migrations.report(userData); UserData.Builder userDataBuilder = UserData.newBuilder(userData); UserSecretData.Builder userSecretDataBuilder = UserSecretData.newBuilder(userSecretData); KeyczarKey keypair = KeyczarUtils.createKey(new KeyMetadata("RSA Key", KeyPurpose.DECRYPT_AND_ENCRYPT, DefaultKeyType.RSA_PRIV)); if (userSecretDataBuilder.getPrivateKeyBuilder().hasKeyczar()) { throw new IllegalStateException(); } userSecretDataBuilder.getPrivateKeyBuilder().setKeyczar(keypair.toString()); if (userDataBuilder.getPublicKeyBuilder().hasKeyczar()) { throw new IllegalStateException(); } userDataBuilder.getPublicKeyBuilder().setKeyczar(KeyczarUtils.getPublicKey(keypair).toString()); SecretStoreData.Builder secretStore = userDataBuilder.getSecretStoreBuilder(); if (!Strings.isNullOrEmpty(password)) { Secrets.setPassword(secretStore, password, secretToken); } else { // Without a password, there's going to be no way to get the key throw new UnsupportedOperationException(); } userSecretData = userSecretDataBuilder.build(); userDataBuilder.setSecretData(Secrets.buildUserSecret(secretToken, userSecretData)); userData = authRepository.getUsers().update(userDataBuilder); return new UserWithSecret(userData, userSecretData, secretToken); } return user; } }