KEYCLOAK-10933 Interfaces for vault SPI
This commit is contained in:
parent
71eed3af06
commit
d2da206d6b
6 changed files with 232 additions and 1 deletions
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright 2019 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* 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 org.keycloak.vault;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
|
||||
/**
|
||||
* Provider interface for a vault. The only purpose of a vault is retrieval of secrets.
|
||||
*/
|
||||
public interface VaultProvider extends Provider {
|
||||
|
||||
/**
|
||||
* Retrieves a secret from vault. The implementation should respect
|
||||
* at least the realm ID to separate the secrets within the vault.
|
||||
* If the secret is retrieved successfully, it is returned;
|
||||
* otherwise this method results into an empty {@link VaultRawSecret#getRawSecret()}.
|
||||
*
|
||||
* This method is intended to be used within a try-with-resources block so that
|
||||
* the secret is destroyed immediately after use.
|
||||
*
|
||||
* Note that it is responsibility of the implementor to provide a way
|
||||
* to destroy the secret in the returned {@link VaultRawSecret#close()} method.
|
||||
*
|
||||
* @param vaultSecretId Identifier of the secret. It corresponds to the value
|
||||
* entered by user in the respective configuration, which in turn
|
||||
* is obtained from the vault when storing the secret.
|
||||
*
|
||||
* @return Always a non-{@code null} value with the raw secret.
|
||||
* Within the returned value, the secret or {@code null} is stored in the
|
||||
* {@link VaultRawSecret#getRawSecret()} return value if the secret was successfully
|
||||
* resolved, or an empty {@link java.util.Optional} if the secret has not been found in the vault.
|
||||
*/
|
||||
VaultRawSecret obtainSecret(String vaultSecretId);
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright 2019 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* 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 org.keycloak.vault;
|
||||
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
||||
/**
|
||||
*/
|
||||
public interface VaultProviderFactory extends ProviderFactory<VaultProvider> {
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2019 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* 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 org.keycloak.vault;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Raw representation of the secret obtained from vault that supports automated cleanup of memory.
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public interface VaultRawSecret extends AutoCloseable {
|
||||
|
||||
/**
|
||||
* Returns the raw secret bytes.
|
||||
* @return If the secret was successfully resolved by vault, returns
|
||||
* an {@link Optional} containing the value returned by the vault
|
||||
* (a valid value can be {@code null}), or an empty {@link Optional}
|
||||
*/
|
||||
Optional<ByteBuffer> getRawSecret();
|
||||
|
||||
/**
|
||||
* Destroys the secret in memory by e.g. overwriting it with random garbage.
|
||||
*/
|
||||
@Override
|
||||
void close();
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright 2019 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* 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 org.keycloak.vault;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
|
||||
/**
|
||||
* SPI for a low-level vault access.
|
||||
*/
|
||||
public class VaultSpi implements Spi {
|
||||
|
||||
@Override
|
||||
public boolean isInternal() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "vault";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Provider> getProviderClass() {
|
||||
return VaultProvider.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||
return VaultProviderFactory.class;
|
||||
}
|
||||
}
|
|
@ -75,3 +75,4 @@ org.keycloak.storage.client.ClientStorageProviderSpi
|
|||
org.keycloak.crypto.SignatureSpi
|
||||
org.keycloak.crypto.ClientSignatureVerifierSpi
|
||||
org.keycloak.crypto.HashSpi
|
||||
org.keycloak.vault.VaultSpi
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright 2019 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* 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 org.keycloak.vault;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* Default raw secret implementation for {@code byte[]}.
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class DefaultVaultRawSecret implements VaultRawSecret {
|
||||
|
||||
private static final VaultRawSecret EMPTY_VAULT_SECRET = new VaultRawSecret() {
|
||||
@Override
|
||||
public Optional<ByteBuffer> getRawSecret() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
};
|
||||
|
||||
private final ByteBuffer rawSecret;
|
||||
|
||||
public static VaultRawSecret forBuffer(Optional<ByteBuffer> buffer) {
|
||||
if (buffer == null || ! buffer.isPresent()) {
|
||||
return EMPTY_VAULT_SECRET;
|
||||
}
|
||||
return new DefaultVaultRawSecret(buffer.get());
|
||||
}
|
||||
|
||||
private DefaultVaultRawSecret(ByteBuffer rawSecret) {
|
||||
this.rawSecret = rawSecret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ByteBuffer> getRawSecret() {
|
||||
return Optional.of(this.rawSecret);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (rawSecret.hasArray()) {
|
||||
ThreadLocalRandom.current().nextBytes(rawSecret.array());
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue