-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add secret export command (#2)
Closes #2
- Loading branch information
1 parent
4790a19
commit 174240f
Showing
19 changed files
with
349 additions
and
80 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 11 additions & 4 deletions
15
...rilabs/keycloak/configurator/commands/configure/entity/ConfigureCommandConfiguration.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,17 @@ | ||
package com.cycrilabs.keycloak.configurator.commands.configure.entity; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
|
||
@AllArgsConstructor | ||
import com.cycrilabs.keycloak.configurator.shared.entity.KeycloakConfiguration; | ||
|
||
import picocli.CommandLine.ParseResult; | ||
|
||
@Getter | ||
public class ConfigureCommandConfiguration { | ||
String configDirectory; | ||
public class ConfigureCommandConfiguration extends KeycloakConfiguration { | ||
private final String configDirectory; | ||
|
||
public ConfigureCommandConfiguration(final ParseResult parseResult) { | ||
super(parseResult); | ||
configDirectory = getMatchedOption(parseResult, "-c"); | ||
} | ||
} |
99 changes: 99 additions & 0 deletions
99
...ain/java/com/cycrilabs/keycloak/configurator/commands/secrets/boundary/ExportSecrets.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
package com.cycrilabs.keycloak.configurator.commands.secrets.boundary; | ||
|
||
import java.io.File; | ||
import java.io.FileNotFoundException; | ||
import java.io.IOException; | ||
import java.net.URISyntaxException; | ||
import java.nio.charset.StandardCharsets; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.nio.file.Paths; | ||
import java.util.Collection; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
|
||
import jakarta.annotation.PostConstruct; | ||
import jakarta.enterprise.context.ApplicationScoped; | ||
import jakarta.inject.Inject; | ||
|
||
import org.apache.commons.io.FileUtils; | ||
import org.apache.velocity.Template; | ||
import org.apache.velocity.runtime.parser.ParseException; | ||
import org.keycloak.admin.client.Keycloak; | ||
import org.keycloak.representations.idm.ClientRepresentation; | ||
|
||
import com.cycrilabs.keycloak.configurator.commands.secrets.entity.ExportSecretsCommandConfiguration; | ||
import com.cycrilabs.keycloak.configurator.shared.control.KeycloakFactory; | ||
import com.cycrilabs.keycloak.configurator.shared.control.VelocityUtils; | ||
|
||
import io.quarkus.logging.Log; | ||
|
||
@ApplicationScoped | ||
public class ExportSecrets { | ||
private static final String TEMPLATE_NAME_PLACEHOLDER = "client-name"; | ||
|
||
@Inject | ||
ExportSecretsCommandConfiguration configuration; | ||
Keycloak keycloak; | ||
|
||
@PostConstruct | ||
public void init() { | ||
keycloak = KeycloakFactory.create(configuration); | ||
} | ||
|
||
public void export() throws IOException, ParseException, URISyntaxException { | ||
final Collection<Template> templates = VelocityUtils.loadTemplates(loadTemplateFiles()); | ||
final List<ClientRepresentation> clients = loadClientSecrets(); | ||
for (final ClientRepresentation client : clients) { | ||
for (final Template template : templates) { | ||
Log.infof("Generating secret file(s) for client '%s.'", client.getClientId()); | ||
writeFiles(client, template); | ||
} | ||
} | ||
} | ||
|
||
private Collection<File> loadTemplateFiles() throws URISyntaxException, FileNotFoundException { | ||
return configuration.getConfigDirectory() == null | ||
? List.of(getDefaultTemplateFile()) | ||
: FileUtils.listFiles(new File(configuration.getConfigDirectory()), null, true); | ||
} | ||
|
||
private File getDefaultTemplateFile() throws FileNotFoundException, URISyntaxException { | ||
return new File(Optional.ofNullable(getClass().getResource("client-name.env")) | ||
.orElseThrow(() -> new FileNotFoundException("Default template not found.")) | ||
.toURI()); | ||
} | ||
|
||
private List<ClientRepresentation> loadClientSecrets() { | ||
return keycloak.realm(configuration.getRealmName()) | ||
.clients() | ||
.findAll() | ||
.stream() | ||
.filter(client -> client.getSecret() != null) | ||
.toList(); | ||
} | ||
|
||
private void writeFiles(final ClientRepresentation client, final Template template) { | ||
final String fileContent = generateFileContent(client, template); | ||
final Path targetFile = getTargetFile(client.getClientId(), template.getName()); | ||
try { | ||
Files.writeString(targetFile, fileContent, StandardCharsets.UTF_8); | ||
} catch (final IOException e) { | ||
Log.errorf("Failed to write file '%s.'", targetFile.toString()); | ||
} | ||
} | ||
|
||
private String generateFileContent(final ClientRepresentation client, final Template template) { | ||
return VelocityUtils.mergeTemplate(template, VelocityUtils.createVelocityContext( | ||
Map.ofEntries( | ||
Map.entry("secret", client.getSecret()) | ||
) | ||
)); | ||
} | ||
|
||
private Path getTargetFile(final String clientId, final String templateName) { | ||
final String filename = templateName.replace(TEMPLATE_NAME_PLACEHOLDER, clientId); | ||
return Paths.get(configuration.getOutputDirectory(), filename); | ||
} | ||
} |
39 changes: 29 additions & 10 deletions
39
...va/com/cycrilabs/keycloak/configurator/commands/secrets/control/ExportSecretsCommand.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,41 @@ | ||
package com.cycrilabs.keycloak.configurator.commands.secrets.control; | ||
|
||
import jakarta.inject.Inject; | ||
|
||
import com.cycrilabs.keycloak.configurator.commands.secrets.boundary.ExportSecrets; | ||
import com.cycrilabs.keycloak.configurator.commands.secrets.entity.ExportSecretsCommandConfiguration; | ||
import com.cycrilabs.keycloak.configurator.shared.control.KeycloakOptions; | ||
|
||
import io.quarkus.logging.Log; | ||
import picocli.CommandLine; | ||
|
||
@CommandLine.Command(name = "export-secrets", mixinStandardHelpOptions = true) | ||
public class ExportSecretsCommand implements Runnable { | ||
@CommandLine.Option(required = true, names = { "-s", "--server" }, | ||
description = "Keycloak server that will be configured.") | ||
String target = ""; | ||
@CommandLine.Option(required = true, names = { "-u", "--username" }, | ||
description = "Username of the admin user that is used for configuration.") | ||
String username = ""; | ||
@CommandLine.Option(required = true, names = { "-p", "--password" }, | ||
description = "Password of the admin user that is used for configuration.") | ||
String password = ""; | ||
@CommandLine.Mixin | ||
KeycloakOptions keycloakOptions; | ||
@CommandLine.Option(required = true, names = { "-r", "--realm" }, | ||
description = "Realm name to export secrets from.") | ||
String realm; | ||
@CommandLine.Option(names = { "-c", "--config" }, | ||
description = "Directory containing templates for secret output files.") | ||
String configDirectory; | ||
@CommandLine.Option(names = { "-o", "--output" }, defaultValue = "./", | ||
description = "Output directory for generate files.") | ||
String outputDirectory; | ||
|
||
@Inject | ||
ExportSecretsCommandConfiguration configuration; | ||
@Inject | ||
ExportSecrets secretExporter; | ||
|
||
@Override | ||
public void run() { | ||
Log.infof("Fetching secrets from target %s.", target); | ||
try { | ||
Log.infof("Exporting secrets from realm '%s'.", configuration.getRealmName()); | ||
secretExporter.export(); | ||
} catch (final Exception e) { | ||
Log.errorf(e, "Failed to export secrets from realm '%s'.", | ||
configuration.getRealmName()); | ||
} | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
...loak/configurator/commands/secrets/control/ExportSecretsCommandConfigurationProducer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package com.cycrilabs.keycloak.configurator.commands.secrets.control; | ||
|
||
import jakarta.enterprise.context.ApplicationScoped; | ||
import jakarta.enterprise.inject.Produces; | ||
|
||
import com.cycrilabs.keycloak.configurator.commands.secrets.entity.ExportSecretsCommandConfiguration; | ||
|
||
import picocli.CommandLine; | ||
|
||
@ApplicationScoped | ||
public class ExportSecretsCommandConfigurationProducer { | ||
@Produces | ||
@ApplicationScoped | ||
ExportSecretsCommandConfiguration createConfiguration( | ||
final CommandLine.ParseResult parseResult) { | ||
return new ExportSecretsCommandConfiguration(parseResult); | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
...labs/keycloak/configurator/commands/secrets/entity/ExportSecretsCommandConfiguration.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package com.cycrilabs.keycloak.configurator.commands.secrets.entity; | ||
|
||
import lombok.Getter; | ||
|
||
import com.cycrilabs.keycloak.configurator.shared.entity.KeycloakConfiguration; | ||
|
||
import picocli.CommandLine.ParseResult; | ||
|
||
@Getter | ||
public class ExportSecretsCommandConfiguration extends KeycloakConfiguration { | ||
private final String realmName; | ||
private final String configDirectory; | ||
private final String outputDirectory; | ||
|
||
public ExportSecretsCommandConfiguration(final ParseResult parseResult) { | ||
super(parseResult); | ||
realmName = getMatchedOption(parseResult, "-r"); | ||
configDirectory = getMatchedOption(parseResult, "-c"); | ||
outputDirectory = getMatchedOption(parseResult, "-o"); | ||
} | ||
} |
Oops, something went wrong.