use of org.keycloak.client.registration.cli.common.CmdStdinContext in project keycloak by keycloak.
the class UpdateCmd method execute.
@Override
public CommandResult execute(CommandInvocation commandInvocation) throws CommandException, InterruptedException {
List<AttributeOperation> attrs = new LinkedList<>();
try {
if (printHelp()) {
return help ? CommandResult.SUCCESS : CommandResult.FAILURE;
}
processGlobalOptions();
String clientId = null;
if (args != null) {
Iterator<String> it = args.iterator();
if (!it.hasNext()) {
throw new IllegalArgumentException("CLIENT_ID not specified");
}
clientId = it.next();
if (clientId.startsWith("-")) {
warnfErr(ParseUtil.CLIENT_OPTION_WARN, clientId);
}
while (it.hasNext()) {
String option = it.next();
switch(option) {
case "-s":
case "--set":
{
if (!it.hasNext()) {
throw new IllegalArgumentException("Option " + option + " requires a value");
}
String[] keyVal = parseKeyVal(it.next());
attrs.add(new AttributeOperation(SET, keyVal[0], keyVal[1]));
break;
}
case "-d":
case "--delete":
{
attrs.add(new AttributeOperation(DELETE, it.next()));
break;
}
default:
{
throw new IllegalArgumentException("Unsupported option: " + option);
}
}
}
}
if (file == null && attrs.size() == 0) {
throw new IllegalArgumentException("No file nor attribute values specified");
}
//
if (file == null && attrs.size() > 0) {
mergeMode = true;
}
CmdStdinContext ctx = new CmdStdinContext();
if (file != null) {
ctx = parseFileOrStdin(file, regType);
regType = ctx.getEndpointType();
}
if (regType == null) {
regType = DEFAULT;
ctx.setEndpointType(regType);
} else if (regType != DEFAULT && regType != OIDC) {
throw new RuntimeException("Update not supported for endpoint type: " + regType.getEndpoint());
}
// initialize config only after reading from stdin,
// to allow proper operation when piping 'get' - which consumes the old
// registration access token, and saves the new one to the config
ConfigData config = loadConfig();
config = copyWithServerInfo(config);
final String server = config.getServerUrl();
final String realm = config.getRealm();
if (token == null) {
// if registration access token is not set via --token, see if it's in the body of any input file
// but first see if it's overridden by --set, or maybe deliberately muted via -d registrationAccessToken
boolean processed = false;
for (AttributeOperation op : attrs) {
if ("registrationAccessToken".equals(op.getKey().toString())) {
processed = true;
if (op.getType() == AttributeOperation.Type.SET) {
token = op.getValue();
}
// otherwise it's delete - meaning it should stay null
break;
}
}
if (!processed) {
token = ctx.getRegistrationAccessToken();
}
}
if (token == null) {
// if registration access token is not set, try use the one from configuration
token = getRegistrationToken(config.sessionRealmConfigData(), clientId);
}
setupTruststore(config, commandInvocation);
String auth = token;
if (auth == null) {
config = ensureAuthInfo(config, commandInvocation);
config = copyWithServerInfo(config);
if (credentialsAvailable(config)) {
auth = ensureToken(config);
}
}
auth = auth != null ? "Bearer " + auth : null;
if (mergeMode) {
InputStream response = doGet(server + "/realms/" + realm + "/clients-registrations/" + regType.getEndpoint() + "/" + urlencode(clientId), APPLICATION_JSON, auth);
String json = readFully(response);
CmdStdinContext ctxremote = new CmdStdinContext();
ctxremote.setContent(json);
ctxremote.setEndpointType(regType);
try {
if (regType == DEFAULT) {
ctxremote.setClient(JsonSerialization.readValue(json, ClientRepresentation.class));
token = ctxremote.getClient().getRegistrationAccessToken();
} else if (regType == OIDC) {
ctxremote.setOidcClient(JsonSerialization.readValue(json, OIDCClientRepresentation.class));
token = ctxremote.getOidcClient().getRegistrationAccessToken();
}
} catch (JsonParseException e) {
throw new RuntimeException("Not a valid JSON document. " + e.getMessage(), e);
} catch (IOException e) {
throw new RuntimeException("Not a valid JSON document", e);
}
// that ensures optimistic locking semantics
if (token != null) {
// we use auth with doPost later
auth = "Bearer " + token;
String newToken = token;
String clientToUpdate = clientId;
saveMergeConfig(cfg -> {
setRegistrationToken(cfg.ensureRealmConfigData(server, realm), clientToUpdate, newToken);
});
}
// merge local representation over remote one
if (ctx.getClient() != null) {
ReflectionUtil.merge(ctx.getClient(), ctxremote.getClient());
} else if (ctx.getOidcClient() != null) {
ReflectionUtil.merge(ctx.getOidcClient(), ctxremote.getOidcClient());
}
ctx = ctxremote;
}
if (attrs.size() > 0) {
ctx = mergeAttributes(ctx, attrs);
}
// now update
InputStream response = doPut(server + "/realms/" + realm + "/clients-registrations/" + regType.getEndpoint() + "/" + urlencode(clientId), APPLICATION_JSON, APPLICATION_JSON, ctx.getContent(), auth);
try {
if (regType == DEFAULT) {
ClientRepresentation clirep = JsonSerialization.readValue(response, ClientRepresentation.class);
outputResult(clirep);
token = clirep.getRegistrationAccessToken();
} else if (regType == OIDC) {
OIDCClientRepresentation clirep = JsonSerialization.readValue(response, OIDCClientRepresentation.class);
outputResult(clirep);
token = clirep.getRegistrationAccessToken();
}
String newToken = token;
String clientToUpdate = clientId;
saveMergeConfig(cfg -> {
setRegistrationToken(cfg.ensureRealmConfigData(server, realm), clientToUpdate, newToken);
});
} catch (IOException e) {
throw new RuntimeException("Failed to process HTTP response", e);
}
return CommandResult.SUCCESS;
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(e.getMessage() + suggestHelp(), e);
} finally {
commandInvocation.stop();
}
}
use of org.keycloak.client.registration.cli.common.CmdStdinContext in project keycloak by keycloak.
the class ParseUtil method parseFileOrStdin.
public static CmdStdinContext parseFileOrStdin(String file, EndpointType type) {
String content = readFileOrStdin(file).trim();
ClientRepresentation client = null;
OIDCClientRepresentation oidcClient = null;
if (type == null) {
// guess the correct endpoint from content of the file
if (content.startsWith("<")) {
// looks like XML
type = EndpointType.SAML2;
} else if (content.startsWith("{")) {
// try parse as ClientRepresentation
try {
client = JsonSerialization.readValue(content, ClientRepresentation.class);
type = EndpointType.DEFAULT;
} catch (JsonParseException e) {
throw new RuntimeException("Failed to read the input document as JSON: " + e.getMessage(), e);
} catch (Exception ignored) {
// deliberately not logged
}
if (client == null) {
// try parse as OIDCClientRepresentation
try {
oidcClient = JsonSerialization.readValue(content, OIDCClientRepresentation.class);
type = EndpointType.OIDC;
} catch (IOException ne) {
throw new RuntimeException("Unable to determine input document type. Use -e TYPE to specify the registration endpoint to use");
} catch (Exception e) {
throw new RuntimeException("Failed to read the input document as JSON", e);
}
}
} else if (content.length() == 0) {
throw new RuntimeException("Document provided by --file option is empty");
} else {
throw new RuntimeException("Unable to determine input document type. Use -e TYPE to specify the registration endpoint to use");
}
}
// check content type, making sure it can be parsed into .json if it's not saml xml
if (content != null) {
try {
if (type == EndpointType.DEFAULT && client == null) {
client = JsonSerialization.readValue(content, ClientRepresentation.class);
} else if (type == EndpointType.OIDC && oidcClient == null) {
oidcClient = JsonSerialization.readValue(content, OIDCClientRepresentation.class);
}
} catch (JsonParseException e) {
throw new RuntimeException("Not a valid JSON document - " + e.getMessage(), e);
} catch (UnrecognizedPropertyException e) {
throw new RuntimeException("Attribute '" + e.getPropertyName() + "' not supported on document type '" + type.getName() + "'", e);
} catch (IOException e) {
throw new RuntimeException("Not a valid JSON document", e);
}
}
CmdStdinContext ctx = new CmdStdinContext();
ctx.setEndpointType(type);
ctx.setContent(content);
ctx.setClient(client);
ctx.setOidcClient(oidcClient);
return ctx;
}
use of org.keycloak.client.registration.cli.common.CmdStdinContext in project keycloak by keycloak.
the class CreateCmd method execute.
@Override
public CommandResult execute(CommandInvocation commandInvocation) throws CommandException, InterruptedException {
List<AttributeOperation> attrs = new LinkedList<>();
try {
if (printHelp()) {
return help ? CommandResult.SUCCESS : CommandResult.FAILURE;
}
processGlobalOptions();
if (args != null) {
Iterator<String> it = args.iterator();
while (it.hasNext()) {
String option = it.next();
switch(option) {
case "-s":
case "--set":
{
if (!it.hasNext()) {
throw new IllegalArgumentException("Option " + option + " requires a value");
}
String[] keyVal = parseKeyVal(it.next());
attrs.add(new AttributeOperation(SET, keyVal[0], keyVal[1]));
break;
}
default:
{
throw new IllegalArgumentException("Unsupported option: " + option);
}
}
}
}
if (file == null && attrs.size() == 0) {
throw new IllegalArgumentException("No file nor attribute values specified");
}
if (outputClient && returnClientId) {
throw new IllegalArgumentException("Options -o and -i are mutually exclusive");
}
// if --token is specified read it
if ("-".equals(token)) {
token = readSecret("Enter Initial Access Token: ", commandInvocation);
}
CmdStdinContext ctx = new CmdStdinContext();
if (file != null) {
ctx = parseFileOrStdin(file, regType);
}
if (ctx.getEndpointType() == null) {
regType = regType != null ? regType : DEFAULT;
ctx.setEndpointType(regType);
} else if (regType != null && ctx.getEndpointType() != regType) {
throw new RuntimeException("Requested endpoint type not compatible with detected configuration format: " + ctx.getEndpointType());
}
if (attrs.size() > 0) {
ctx = mergeAttributes(ctx, attrs);
}
String contentType = getExpectedContentType(ctx.getEndpointType());
ConfigData config = loadConfig();
config = copyWithServerInfo(config);
if (token == null) {
// if initial token is not set, try use the one from configuration
token = config.sessionRealmConfigData().getInitialToken();
}
setupTruststore(config, commandInvocation);
String auth = token;
if (auth == null) {
config = ensureAuthInfo(config, commandInvocation);
config = copyWithServerInfo(config);
if (credentialsAvailable(config)) {
auth = ensureToken(config);
}
}
auth = auth != null ? "Bearer " + auth : null;
final String server = config.getServerUrl();
final String realm = config.getRealm();
InputStream response = doPost(server + "/realms/" + realm + "/clients-registrations/" + ctx.getEndpointType().getEndpoint(), contentType, HttpUtil.APPLICATION_JSON, ctx.getContent(), auth);
try {
if (ctx.getEndpointType() == DEFAULT || ctx.getEndpointType() == SAML2) {
ClientRepresentation client = JsonSerialization.readValue(response, ClientRepresentation.class);
outputResult(client.getClientId(), client);
saveMergeConfig(cfg -> {
setRegistrationToken(cfg.ensureRealmConfigData(server, realm), client.getClientId(), client.getRegistrationAccessToken());
});
} else if (ctx.getEndpointType() == OIDC) {
OIDCClientRepresentation client = JsonSerialization.readValue(response, OIDCClientRepresentation.class);
outputResult(client.getClientId(), client);
saveMergeConfig(cfg -> {
setRegistrationToken(cfg.ensureRealmConfigData(server, realm), client.getClientId(), client.getRegistrationAccessToken());
});
} else {
printOut("Response from server: " + readFully(response));
}
} catch (UnrecognizedPropertyException e) {
throw new RuntimeException("Failed to process HTTP reponse - " + e.getMessage(), e);
} catch (IOException e) {
throw new RuntimeException("Failed to process HTTP response", e);
}
return CommandResult.SUCCESS;
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(e.getMessage() + suggestHelp(), e);
} finally {
commandInvocation.stop();
}
}
Aggregations