use of org.keycloak.client.registration.cli.common.AttributeOperation 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.AttributeOperation in project keycloak by keycloak.
the class ReflectionUtilTest method testSettingAttibutes.
@Test
public void testSettingAttibutes() {
Data data = new Data();
LinkedList<AttributeOperation> attrs = new LinkedList<>();
attrs.add(new AttributeOperation(SET, "longAttr", "42"));
attrs.add(new AttributeOperation(SET, "strAttr", "not null"));
attrs.add(new AttributeOperation(SET, "strList+", "two"));
attrs.add(new AttributeOperation(SET, "strList+", "three"));
attrs.add(new AttributeOperation(SET, "strList[0]+", "one"));
attrs.add(new AttributeOperation(SET, "config", "{\"key1\": \"value1\"}"));
attrs.add(new AttributeOperation(SET, "config.key2", "value2"));
attrs.add(new AttributeOperation(SET, "nestedConfig", "{\"key1\": {\"sub key1\": \"sub value1\"}}"));
attrs.add(new AttributeOperation(SET, "nestedConfig.key1.\"sub key2\"", "sub value2"));
attrs.add(new AttributeOperation(SET, "nested.strList", "[1,2,3,4]"));
attrs.add(new AttributeOperation(SET, "nested.dataList+", "{\"baseAttr\": \"item1\", \"strList\": [\"confidential\", \"public\"]}"));
attrs.add(new AttributeOperation(SET, "nested.dataList+", "{\"baseAttr\": \"item2\", \"strList\": [\"external\"]}"));
attrs.add(new AttributeOperation(SET, "nested.dataList[1].baseAttr", "changed item2"));
attrs.add(new AttributeOperation(SET, "nested.nested.strList", "[\"first\",\"second\"]"));
attrs.add(new AttributeOperation(DELETE, "nested.strList[1]"));
attrs.add(new AttributeOperation(SET, "nested.nested.nested", "{\"baseAttr\": \"NEW VALUE\", \"strList\": [true, false]}"));
attrs.add(new AttributeOperation(SET, "nested.strAttr", "NOT NULL"));
attrs.add(new AttributeOperation(DELETE, "nested.strAttr"));
ReflectionUtil.setAttributes(data, attrs);
Assert.assertEquals("longAttr", Long.valueOf(42), data.getLongAttr());
Assert.assertEquals("strAttr", "not null", data.getStrAttr());
Assert.assertEquals("strList", Arrays.asList("one", "two", "three"), data.getStrList());
Map<String, String> expectedMap = new HashMap<>();
expectedMap.put("key1", "value1");
expectedMap.put("key2", "value2");
Assert.assertEquals("config", expectedMap, data.getConfig());
expectedMap = new HashMap<>();
expectedMap.put("sub key1", "sub value1");
expectedMap.put("sub key2", "sub value2");
Assert.assertNotNull("nestedConfig", data.getNestedConfig());
Assert.assertEquals("nestedConfig has one element", 1, data.getNestedConfig().size());
Assert.assertEquals("nestedConfig.key1", expectedMap, data.getNestedConfig().get("key1"));
Data nested = data.getNested();
Assert.assertEquals("nested.strAttr", null, nested.getStrAttr());
Assert.assertEquals("nested.strList", Arrays.asList("1", "3", "4"), nested.getStrList());
Assert.assertEquals("nested.dataList[0].baseAttr", "item1", nested.getDataList().get(0).getBaseAttr());
Assert.assertEquals("nested.dataList[0].strList", Arrays.asList("confidential", "public"), nested.getDataList().get(0).getStrList());
Assert.assertEquals("nested.dataList[1].baseAttr", "changed item2", nested.getDataList().get(1).getBaseAttr());
Assert.assertEquals("nested.dataList[1].strList", Arrays.asList("external"), nested.getDataList().get(1).getStrList());
nested = nested.getNested();
Assert.assertEquals("nested.nested.strList", Arrays.asList("first", "second"), nested.getStrList());
nested = nested.getNested();
Assert.assertEquals("nested.nested.nested.baseAttr", "NEW VALUE", nested.getBaseAttr());
Assert.assertEquals("nested.nested.nested.strList", Arrays.asList("true", "false"), nested.getStrList());
}
use of org.keycloak.client.registration.cli.common.AttributeOperation in project keycloak by keycloak.
the class ReflectionUtil method setAttributes.
public static void setAttributes(Object client, List<AttributeOperation> attrs) {
for (AttributeOperation item : attrs) {
AttributeKey attr = item.getKey();
Object nested = client;
List<AttributeKey.Component> cs = attr.getComponents();
for (int i = 0; i < cs.size(); i++) {
AttributeKey.Component c = cs.get(i);
Class type = nested.getClass();
Field field = null;
if (!isMapType(type)) {
Map<String, Field> fields = getAttrFieldsForType(type);
if (fields == null) {
throw new AttributeException(attr.toString(), "Unexpected condition - unknown type: " + type);
}
field = fields.get(c.getName());
Class parent = type;
while (field == null) {
parent = parent.getSuperclass();
if (parent == Object.class) {
throw new AttributeException(attr.toString(), "Unknown attribute '" + c.getName() + "' on " + client.getClass());
}
fields = getAttrFieldsForType(parent);
field = fields.get(c.getName());
}
}
// if it's a 'basic' type we directly use setter
type = field == null ? type : field.getType();
if (isBasicType(type)) {
if (i < cs.size() - 1) {
throw new AttributeException(attr.toString(), "Attribute is of primitive type, and can't be nested further: " + c);
}
try {
Object val = convertValueToType(item.getValue(), type);
field.set(nested, val);
} catch (Exception e) {
throw new AttributeException(attr.toString(), "Failed to set attribute " + attr, e);
}
} else if (isListType(type)) {
if (i < cs.size() - 1) {
// not the target component
try {
nested = field.get(nested);
} catch (Exception e) {
throw new AttributeException(attr.toString(), "Failed to get attribute \"" + c + "\" in " + attr, e);
}
if (c.getIndex() >= 0) {
// list item
// get idx-th item
List l = (List) nested;
if (c.getIndex() >= l.size()) {
throw new AttributeException(attr.toString(), "Array index out of bounds for \"" + c + "\" in " + attr);
}
nested = l.get(c.getIndex());
}
} else {
// target component
Class itype = type;
Type gtype = field.getGenericType();
if (gtype instanceof ParameterizedType) {
Type[] typeArgs = ((ParameterizedType) gtype).getActualTypeArguments();
if (typeArgs.length >= 1 && typeArgs[0] instanceof Class) {
itype = (Class) typeArgs[0];
} else {
itype = String.class;
}
}
if (c.getIndex() >= 0 || attr.isAppend()) {
// some list item
// get the list first
List target;
try {
target = (List) field.get(nested);
} catch (Exception e) {
throw new AttributeException(attr.toString(), "Failed to get list attribute: " + attr, e);
}
// now replace or add idx-th item
if (target == null) {
target = createNewList(type);
try {
field.set(nested, target);
} catch (Exception e) {
throw new AttributeException(attr.toString(), "Failed to set list attribute " + attr, e);
}
}
if (c.getIndex() >= target.size()) {
throw new AttributeException(attr.toString(), "Array index out of bounds for \"" + c + "\" in " + attr);
}
if (attr.isAppend()) {
try {
Object value = convertValueToType(item.getValue(), itype);
if (c.getIndex() >= 0) {
target.add(c.getIndex(), value);
} else {
target.add(value);
}
} catch (Exception e) {
throw new AttributeException(attr.toString(), "Failed to set list attribute " + attr, e);
}
} else {
if (item.getType() == AttributeOperation.Type.SET) {
try {
Object value = convertValueToType(item.getValue(), itype);
target.set(c.getIndex(), value);
} catch (Exception e) {
throw new AttributeException(attr.toString(), "Failed to set list attribute " + attr, e);
}
} else {
try {
target.remove(c.getIndex());
} catch (Exception e) {
throw new AttributeException(attr.toString(), "Failed to remove list attribute " + attr, e);
}
}
}
} else {
// set the whole list field itself
List value = createNewList(type);
;
if (item.getType() == AttributeOperation.Type.SET) {
List converted = convertValueToList(item.getValue(), itype);
value.addAll(converted);
}
try {
field.set(nested, value);
} catch (Exception e) {
throw new AttributeException(attr.toString(), "Failed to set list attribute " + attr, e);
}
}
}
} else {
// object type
if (i < cs.size() - 1) {
// not the target component
Object value;
if (field == null) {
if (isMapType(nested.getClass())) {
value = ((Map) nested).get(c.getName());
} else {
throw new RuntimeException("Unexpected condition while processing: " + attr);
}
} else {
try {
value = field.get(nested);
} catch (Exception e) {
throw new AttributeException(attr.toString(), "Failed to get attribute \"" + c + "\" in " + attr, e);
}
}
if (value == null) {
// create the target attribute
if (isMapType(nested.getClass())) {
throw new RuntimeException("Creating nested object trees not supported");
} else {
try {
value = createNewObject(type);
field.set(nested, value);
} catch (Exception e) {
throw new AttributeException(attr.toString(), "Failed to set attribute " + attr, e);
}
}
}
nested = value;
} else {
// todo implement map put
if (isMapType(nested.getClass())) {
try {
((Map) nested).put(c.getName(), item.getValue());
} catch (Exception e) {
throw new AttributeException(attr.toString(), "Failed to set map key " + attr, e);
}
} else {
try {
Object value = convertValueToType(item.getValue(), type);
field.set(nested, value);
} catch (Exception e) {
throw new AttributeException(attr.toString(), "Failed to set attribute " + attr, e);
}
}
}
}
}
}
}
use of org.keycloak.client.registration.cli.common.AttributeOperation 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