Beispiel #1
0
  public static List<RoleRepresentation> getRealmRoles(HttpServletRequest req) throws Failure {
    KeycloakSecurityContext session =
        (KeycloakSecurityContext) req.getAttribute(KeycloakSecurityContext.class.getName());

    HttpClient client = new HttpClientBuilder().disableTrustManager().build();
    try {
      HttpGet get =
          new HttpGet(
              AdapterUtils.getOriginForRestCalls(req.getRequestURL().toString(), session)
                  + "/auth/admin/realms/demo/roles");
      get.addHeader("Authorization", "Bearer " + session.getTokenString());
      try {
        HttpResponse response = client.execute(get);
        if (response.getStatusLine().getStatusCode() != 200) {
          throw new Failure(response.getStatusLine().getStatusCode());
        }
        HttpEntity entity = response.getEntity();
        InputStream is = entity.getContent();
        try {
          return JsonSerialization.readValue(is, TypedList.class);
        } finally {
          is.close();
        }
      } catch (IOException e) {
        throw new RuntimeException(e);
      }
    } finally {
      client.getConnectionManager().shutdown();
    }
  }
 protected boolean validateRecaptcha(
     ValidationContext context, boolean success, String captcha, String secret) {
   HttpClient httpClient =
       context.getSession().getProvider(HttpClientProvider.class).getHttpClient();
   HttpPost post = new HttpPost("https://www.google.com/recaptcha/api/siteverify");
   List<NameValuePair> formparams = new LinkedList<>();
   formparams.add(new BasicNameValuePair("secret", secret));
   formparams.add(new BasicNameValuePair("response", captcha));
   formparams.add(new BasicNameValuePair("remoteip", context.getConnection().getRemoteAddr()));
   try {
     UrlEncodedFormEntity form = new UrlEncodedFormEntity(formparams, "UTF-8");
     post.setEntity(form);
     HttpResponse response = httpClient.execute(post);
     InputStream content = response.getEntity().getContent();
     try {
       Map json = JsonSerialization.readValue(content, Map.class);
       Object val = json.get("success");
       success = Boolean.TRUE.equals(val);
     } finally {
       content.close();
     }
   } catch (Exception e) {
     logger.error("Recaptcha failed", e);
   }
   return success;
 }
Beispiel #3
0
 @Test
 public void testReadOIDCClientRepWithJWKS() throws IOException {
   String stringRep =
       "{\"token_endpoint_auth_method\": \"private_key_jwt\", \"subject_type\": \"public\", \"jwks_uri\": null, \"jwks\": {\"keys\": [{\"use\": \"enc\", \"e\": \"AQAB\", \"d\": \"lZQv0_81euRLeUYU84Aodh0ar7ymDlzWP5NMra4Jklkb-lTBWkI-u4RMsPqGYyW3KHRoL_pgzZXSzQx8RLQfER6timRWb--NxMMKllZubByU3RqH2ooNuocJurspYiXkznPW1Mg9DaNXL0C2hwWPQHTeUVISpjgi5TCOV1ccWVyksFruya_VNL1CIByB-L0GL1rqbKv32cDwi2A3_jJa61cpzfLSIBe-lvCO6tuiDsR4qgJnUwnndQFwEI_4mLmD3iNWXrc8N-poleV8mBfMqBB5fWwy_ZTFCpmQ5AywGmctaik_wNhMoWuA4tUfY6_1LdKld-5Cjq55eLtuJjtvuQ\", \"n\": \"tx3Hjdbc19lkTiohbJrNj4jf2_90MEE122CRrwtFu6saDywKcG7Bi7w2FMAK2oTkuWfqhWRb5BEGmnSXdiCEPO5d-ytqP3nwlZXHaCDYscpP8bB4YLhvCn7R8Efw6gwQle24QPRP3lYoFeuUbDUq7GKA5SfaZUvWoeWjqyLIaBspKQsC26_Umx1E4IXLrMSL6nkRnrYcVZBAXrYCeTP1XtsV38_lZVJfHSaJaUy4PKaj3yvgm93EV2CXybPti7CCMXZ34VqqWiF64pQjZsPu3ZTr7ha_TTQq499-zYRQNDvIVsBDLQQIgrbctuGqj6lrXb31Jj3JIEYqH_4h5X9d0Q\", \"q\": \"1q-r-bmMFbIzrLK2U3elksZq8CqUqZxlSfkGMZuVkxgYMS-e4FPzEp2iirG-eO11aa0cpMMoBdTnVdGJ_ZUR93w0lGf9XnQAJqxP7eOsrUoiW4VWlWH4WfOiLgpO-pFtyTz_JksYYaotc_Z3Zy-Szw6a39IDbuYGy1qL-15oQuc\", \"p\": \"2lrYPppRbcQWu4LtWN6tOVUrtCOPv1eLTKTc7q8vCMcem1Ox5QFB7KnUtNZ5Ni7wnZUeVDfimNebtjNsGvDSrpgIlo9dEnFBQsQIkzZ2SkoYfgmF8hNdi6P-BfRjdgYouy4c6xAnGDgSMTip1YnPRyvbMaoYT9E_tEcBW5wOeoc\", \"kid\": \"a0\", \"kty\": \"RSA\"}, {\"use\": \"sig\", \"e\": \"AQAB\", \"d\": \"DodXDEtkovWWGsMEXYy_nEEMCWyROMOebCnCv0ey3i4M4bh2dmwqgz0e-IKQAFlGiMkidGL1lNbq0uFS04FbuRAR06dYw1cbrNbDdhrWFxKTd1L5D9p-x-gW-YDWhpI8rUGRa76JXkOSxZUbg09_QyUd99CXAHh-FXi_ZkIKD8hK6FrAs68qhLf8MNkUv63DTduw7QgeFfQivdopePxyGuMk5n8veqwsUZsklQkhNlTYQqeM1xb2698ZQcNYkl0OssEsSJKRjXt-LRPowKrdvTuTo2p--HMI0pIEeFs7H_u5OW3jihjvoFClGPynHQhgWmQzlQRvWRXh6FhDVqFeGQ\", \"n\": \"zfZzttF7HmnTYwSMPdxKs5AoczbNS2mOPz-tN1g4ljqI_F1DG8cgQDcN_VDufxoFGRERo2FK6WEN41LhbGEyP6uL6wW6Cy29qE9QZcvY5mXrncndRSOkNcMizvuEJes_fMYrmP_lPiC6kWiqItTk9QBWqJfiYKhCx9cSDXsBmJXn3KWQCVHvj1ANFWW0CWLMKlWN-_NMNLIWJN_pEAocTZMzxSFBK1b5_5J8ZS7hfWRF6MQmjsJcz2jzA21SQZNpre3kwnTGRSwo05sAS-TyeadDqQPWgbqX69UzcGq5irhzN8cpZ_JaTk3Y_uV6owanTZLVvCgdjaAnMYeZhb0KFw\", \"q\": \"5E5XKK5njT-zzRqqTeY2tgP9PJBACeaH_xQRHZ_1ydE7tVd7HdgdaEHfQ1jvKIHFkknWWOBAY1mlBc4YDirLShB_voShD8C-Hx3nF5sne5fleVfU-sZy6Za4B2U75PcE62oZgCPauOTAEm9Xuvrt5aMMovyzR8ecJZhm9bw7naU\", \"p\": \"5vJHCSM3H3q4RltYzENC9RyZZV8EUmpkv9moyguT5t-BUGA-T4W_FGIxzOPXRWOckIplKkoDKhavUeNmTZMCUcue0nkICSJpvNE4Nb2p5PZk_QqSdQNvCasQtdojEG0AmfVD85SU551CYxJdLdDFOqyK2entpMr8lhokem189As\", \"kid\": \"a1\", \"kty\": \"RSA\"}, {\"d\": \"S4_OufhLBgXFMgIDMI1zlVe2uCExpcEAQ80J_lXfS8I\", \"use\": \"sig\", \"crv\": \"P-256\", \"kty\": \"EC\", \"y\": \"DBdNyq30mXmUs_BIvKMqaTTNO7HDhCi0YiC8GciwNYk\", \"x\": \"cYwzBoyjRjxj334bRTqanONf7DUYK-6TgiuN0DixJAk\", \"kid\": \"a2\"}, {\"d\": \"33TnYgdJtWAiVosKqUnz0zSmvWTbsx5-6pceynW6Xck\", \"use\": \"enc\", \"crv\": \"P-256\", \"kty\": \"EC\", \"y\": \"Cula95Eix1Ia77St3OULe6-UKWs5I06nmdfUzhXUQTs\", \"x\": \"wk8HBVxNNzj1gJBxPmmx9XYW1L61ObBGzxpRa6_OqWU\", \"kid\": \"a3\"}]}, \"application_type\": \"web\", \"contacts\": [\"[email protected]\"], \"post_logout_redirect_uris\": [\"https://op.certification.openid.net:60784/logout\"], \"redirect_uris\": [\"https://op.certification.openid.net:60784/authz_cb\"], \"response_types\": [\"code\"], \"require_auth_time\": true, \"grant_types\": [\"authorization_code\"], \"default_max_age\": 3600}";
   OIDCClientRepresentation clientRep =
       JsonSerialization.readValue(stringRep, OIDCClientRepresentation.class);
   Assert.assertNotNull(clientRep.getJwks());
 }
Beispiel #4
0
 public static RealmRepresentation loadJson(String path) {
   InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
   try {
     return JsonSerialization.readValue(is, RealmRepresentation.class);
   } catch (IOException e) {
     throw new RuntimeException(e);
   }
 }
 public RealmRepresentation loadJson(String path) throws IOException {
   InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
   ByteArrayOutputStream os = new ByteArrayOutputStream();
   int c;
   while ((c = is.read()) != -1) {
     os.write(c);
   }
   byte[] bytes = os.toByteArray();
   return JsonSerialization.readValue(bytes, RealmRepresentation.class);
 }
Beispiel #6
0
 @Test
 public void testOtherClaims() throws Exception {
   String json =
       "{ \"floatData\" : 555.5,"
           + "\"boolData\": true, "
           + "\"intData\": 1234,"
           + "\"array\": [ \"val\", \"val2\"] }";
   JsonWebToken token = JsonSerialization.readValue(json, JsonWebToken.class);
   System.out.println(token.getOtherClaims().get("floatData").getClass().getName());
   System.out.println(token.getOtherClaims().get("boolData").getClass().getName());
   System.out.println(token.getOtherClaims().get("intData").getClass().getName());
   System.out.println(token.getOtherClaims().get("array").getClass().getName());
 }
Beispiel #7
0
 @Test
 public void testReadOIDCClientRepWithPairwise() throws IOException {
   String stringRep =
       "{\"subject_type\": \"pairwise\", \"jwks_uri\": \"https://op.certification.openid.net:60720/export/jwk_60720.json\", \"contacts\": [\"[email protected]\"], \"application_type\": \"web\", \"grant_types\": [\"authorization_code\"], \"post_logout_redirect_uris\": [\"https://op.certification.openid.net:60720/logout\"], \"redirect_uris\": [\"https://op.certification.openid.net:60720/authz_cb\"], \"response_types\": [\"code\"], \"require_auth_time\": true, \"default_max_age\": 3600}";
   OIDCClientRepresentation clientRep =
       JsonSerialization.readValue(stringRep, OIDCClientRepresentation.class);
   Assert.assertEquals("pairwise", clientRep.getSubjectType());
   Assert.assertTrue(clientRep.getRequireAuthTime());
   Assert.assertEquals(3600, clientRep.getDefaultMaxAge().intValue());
   Assert.assertEquals(1, clientRep.getRedirectUris().size());
   Assert.assertEquals(
       "https://op.certification.openid.net:60720/authz_cb", clientRep.getRedirectUris().get(0));
   Assert.assertNull(clientRep.getJwks());
 }
Beispiel #8
0
  @Test
  public void testUnwrap() throws Exception {
    // just experimenting with unwrapped and any properties
    IDToken test = new IDToken();
    test.getOtherClaims().put("phone_number", "978-666-0000");
    test.getOtherClaims().put("email_verified", "true");
    test.getOtherClaims().put("yo", "true");
    Map<String, String> nested = new HashMap<String, String>();
    nested.put("foo", "bar");
    test.getOtherClaims().put("nested", nested);
    String json = JsonSerialization.writeValueAsPrettyString(test);
    System.out.println(json);

    test = JsonSerialization.readValue(json, IDToken.class);
    System.out.println("email_verified property: " + test.getEmailVerified());
    System.out.println("property: " + test.getPhoneNumber());
    System.out.println("map: " + test.getOtherClaims().get("phone_number"));
    Assert.assertNotNull(test.getPhoneNumber());
    Assert.assertNotNull(test.getOtherClaims().get("yo"));
    Assert.assertNull(test.getOtherClaims().get("phone_number"));
    nested = (Map<String, String>) test.getOtherClaims().get("nested");
    Assert.assertNotNull(nested);
    Assert.assertNotNull(nested.get("foo"));
  }
  @Override
  public void postInit(KeycloakSessionFactory factory) {
    factory.register(
        event -> {
          if (event instanceof ClientRemovedEvent) {
            KeycloakSession keycloakSession = ((ClientRemovedEvent) event).getKeycloakSession();
            AuthorizationProvider provider =
                keycloakSession.getProvider(AuthorizationProvider.class);
            PolicyStore policyStore = provider.getStoreFactory().getPolicyStore();
            ClientModel removedClient = ((ClientRemovedEvent) event).getClient();

            policyStore
                .findByType(getId())
                .forEach(
                    policy -> {
                      List<String> clients = new ArrayList<>();

                      for (String clientId : getClients(policy)) {
                        if (!clientId.equals(removedClient.getId())) {
                          clients.add(clientId);
                        }
                      }

                      try {
                        if (clients.isEmpty()) {
                          policyStore
                              .findDependentPolicies(policy.getId())
                              .forEach(
                                  dependentPolicy -> {
                                    dependentPolicy.removeAssociatedPolicy(policy);
                                  });
                          policyStore.delete(policy.getId());
                        } else {
                          policy
                              .getConfig()
                              .put("clients", JsonSerialization.writeValueAsString(clients));
                        }
                      } catch (IOException e) {
                        throw new RuntimeException(
                            "Error while synchronizing clients with policy ["
                                + policy.getName()
                                + "].",
                            e);
                      }
                    });
          }
        });
  }
Beispiel #10
0
  @Test
  public void testParsingSystemProps() throws IOException {
    System.setProperty("my.host", "foo");
    System.setProperty("con.pool.size", "200");
    System.setProperty("allow.any.hostname", "true");

    InputStream is = getClass().getClassLoader().getResourceAsStream("keycloak.json");

    AdapterConfig config = JsonSerialization.readValue(is, AdapterConfig.class, true);
    Assert.assertEquals("http://foo:8080/auth", config.getAuthServerUrl());
    Assert.assertEquals("external", config.getSslRequired());
    Assert.assertEquals("angular-product${non.existing}", config.getResource());
    Assert.assertTrue(config.isPublicClient());
    Assert.assertTrue(config.isAllowAnyHostname());
    Assert.assertEquals(100, config.getCorsMaxAge());
    Assert.assertEquals(200, config.getConnectionPoolSize());
  }
  static String[] getClients(Policy policy) {
    String clients = policy.getConfig().get("clients");

    if (clients != null) {
      try {
        return JsonSerialization.readValue(clients.getBytes(), String[].class);
      } catch (IOException e) {
        throw new RuntimeException(
            "Could not parse clients ["
                + clients
                + "] from policy config ["
                + policy.getName()
                + "].",
            e);
      }
    }

    return new String[] {};
  }
Beispiel #12
0
  public static ModuleRepresentation getModuleByApp(String moduleName) {
    HttpClient client = new HttpClientBuilder().disableTrustManager().build();

    try {
      HttpGet get =
          new HttpGet("https://ssopoc.prudential.com.sg/auth/modules/" + moduleName + "/info");
      HttpResponse response = client.execute(get);

      if (response.getStatusLine().getStatusCode() != 200) {
        // throw new Failure(response.getStatusLine().getStatusCode());
        return null;
      }
      HttpEntity entity = response.getEntity();
      InputStream is = entity.getContent();

      // Create BufferedReader object
      BufferedReader bReader = new BufferedReader(new InputStreamReader(is));
      StringBuffer sbfFileContents = new StringBuffer();
      String line = null;

      // read file line by line
      while ((line = bReader.readLine()) != null) {
        sbfFileContents.append(line).append(" ");
      }

      // finally convert StringBuffer object to String!
      // log.info(sbfFileContents.toString());

      try {
        return JsonSerialization.readValue(sbfFileContents.toString(), ModuleRepresentation.class);
      } finally {
        is.close();
      }

    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      client.getConnectionManager().shutdown();
    }

    return null;
  }
  private String loadCustomers(HttpServletRequest req, String refreshToken)
      throws ServletException, IOException {
    // Retrieve accessToken first with usage of refresh (offline) token from DB
    String accessToken = null;
    try {
      KeycloakDeployment deployment = getDeployment(req);
      AccessTokenResponse response = ServerRequest.invokeRefresh(deployment, refreshToken);
      accessToken = response.getToken();
    } catch (ServerRequest.HttpFailure failure) {
      return "Failed to refresh token. Status from auth-server request: "
          + failure.getStatus()
          + ", Error: "
          + failure.getError();
    }

    // Load customers now
    HttpGet get =
        new HttpGet(UriUtils.getOrigin(req.getRequestURL().toString()) + "/database/customers");
    get.addHeader("Authorization", "Bearer " + accessToken);

    HttpResponse response = getHttpClient().execute(get);
    InputStream is = response.getEntity().getContent();
    try {
      if (response.getStatusLine().getStatusCode() != 200) {
        return "Error when loading customer. Status: "
            + response.getStatusLine().getStatusCode()
            + ", error: "
            + StreamUtil.readString(is);
      } else {
        List<String> list = JsonSerialization.readValue(is, TypedList.class);
        StringBuilder result = new StringBuilder();
        for (String customer : list) {
          result.append(customer + "<br />");
        }
        return result.toString();
      }
    } finally {
      is.close();
    }
  }
  public static List<String> getProducts(HttpServletRequest request) {
    // This is really the worst code ever. The ServletOAuthClient is obtained by getting a context
    // attribute
    // that is set in the Bootstrap context listenr in this project.
    // You really should come up with a better way to initialize
    // and obtain the ServletOAuthClient.  I actually suggest downloading the ServletOAuthClient
    // code
    // and take a look how it works.
    ServletOAuthClient oAuthClient =
        (ServletOAuthClient)
            request.getServletContext().getAttribute(ServletOAuthClient.class.getName());
    String token = null;
    try {
      token = oAuthClient.getBearerToken(request);
    } catch (IOException e) {
      throw new RuntimeException(e);
    } catch (TokenGrantRequest.HttpFailure failure) {
      throw new RuntimeException(failure);
    }

    HttpClient client = oAuthClient.getClient();

    HttpGet get = new HttpGet("http://localhost:8080/database/products");
    get.addHeader("Authorization", "Bearer " + token);
    try {
      HttpResponse response = client.execute(get);
      HttpEntity entity = response.getEntity();
      InputStream is = entity.getContent();
      try {
        return JsonSerialization.readValue(is, TypedList.class);
      } finally {
        is.close();
      }
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }
Beispiel #15
0
  @Test
  public void addUserTest() throws Throwable {
    AddUser.main(new String[] {"-u", "addusertest-admin", "-p", "password"});
    assertEquals(1, dir.listFiles().length);

    List<RealmRepresentation> realms =
        JsonSerialization.readValue(
            new FileInputStream(new File(dir, "keycloak-add-user.json")),
            new TypeReference<List<RealmRepresentation>>() {});
    assertEquals(1, realms.size());
    assertEquals(1, realms.get(0).getUsers().size());

    UserRepresentation user = realms.get(0).getUsers().get(0);
    assertEquals(new Integer(100000), user.getCredentials().get(0).getHashIterations());
    assertNull(user.getCredentials().get(0).getValue());

    CredentialRepresentation credentials = user.getCredentials().get(0);

    assertEquals(Pbkdf2PasswordHashProvider.ID, credentials.getAlgorithm());
    assertEquals(new Integer(100000), credentials.getHashIterations());

    KeycloakServer server = new KeycloakServer();
    try {
      server.start();

      Keycloak keycloak =
          Keycloak.getInstance(
              "http://localhost:8081/auth",
              "master",
              "addusertest-admin",
              "password",
              Constants.ADMIN_CLI_CLIENT_ID);
      keycloak.realms().findAll();

      RealmRepresentation testRealm = new RealmRepresentation();
      testRealm.setEnabled(true);
      testRealm.setId("test");
      testRealm.setRealm("test");

      keycloak.realms().create(testRealm);

      RealmResource realm = keycloak.realm("master");

      List<UserRepresentation> users =
          realm.users().search("addusertest-admin", null, null, null, null, null);
      assertEquals(1, users.size());

      UserRepresentation created = users.get(0);
      assertNotNull(created.getCreatedTimestamp());

      UserResource userResource = realm.users().get(created.getId());

      List<RoleRepresentation> realmRoles = userResource.roles().realmLevel().listAll();

      assertRoles(realmRoles, "admin", "offline_access");

      List<ClientRepresentation> clients = realm.clients().findAll();
      String accountId = null;
      for (ClientRepresentation c : clients) {
        if (c.getClientId().equals("account")) {
          accountId = c.getId();
        }
      }

      List<RoleRepresentation> accountRoles = userResource.roles().clientLevel(accountId).listAll();

      assertRoles(accountRoles, "view-profile", "manage-account");

      keycloak.close();

      assertEquals(0, dir.listFiles().length);
    } finally {
      server.stop();
    }
  }
  @Override
  protected BrokeredIdentityContext getFederatedIdentity(String response) {
    AccessTokenResponse tokenResponse = null;
    try {
      tokenResponse = JsonSerialization.readValue(response, AccessTokenResponse.class);
    } catch (IOException e) {
      throw new IdentityBrokerException("Could not decode access token response.", e);
    }
    PublicKey key = getExternalIdpKey();
    String accessToken = verifyAccessToken(key, tokenResponse);

    String encodedIdToken = tokenResponse.getIdToken();

    JsonWebToken idToken = validateToken(key, encodedIdToken);

    try {
      String id = idToken.getSubject();
      BrokeredIdentityContext identity = new BrokeredIdentityContext(id);
      String name = (String) idToken.getOtherClaims().get(IDToken.NAME);
      String preferredUsername = (String) idToken.getOtherClaims().get(IDToken.PREFERRED_USERNAME);
      String email = (String) idToken.getOtherClaims().get(IDToken.EMAIL);

      if (getConfig().getUserInfoUrl() != null
          && (id == null || name == null || preferredUsername == null || email == null)) {
        SimpleHttp request =
            JsonSimpleHttp.doGet(getConfig().getUserInfoUrl())
                .header("Authorization", "Bearer " + accessToken);
        JsonNode userInfo = JsonSimpleHttp.asJson(request);

        id = getJsonProperty(userInfo, "sub");
        name = getJsonProperty(userInfo, "name");
        preferredUsername = getJsonProperty(userInfo, "preferred_username");
        email = getJsonProperty(userInfo, "email");
        AbstractJsonUserAttributeMapper.storeUserProfileForMapper(
            identity, userInfo, getConfig().getAlias());
      }
      identity.getContextData().put(FEDERATED_ACCESS_TOKEN_RESPONSE, tokenResponse);
      identity.getContextData().put(VALIDATED_ID_TOKEN, idToken);
      processAccessTokenResponse(identity, key, tokenResponse);

      identity.setId(id);
      identity.setName(name);
      identity.setEmail(email);

      identity.setBrokerUserId(getConfig().getAlias() + "." + id);
      if (tokenResponse.getSessionState() != null) {
        identity.setBrokerSessionId(getConfig().getAlias() + "." + tokenResponse.getSessionState());
      }

      if (preferredUsername == null) {
        preferredUsername = email;
      }

      if (preferredUsername == null) {
        preferredUsername = id;
      }

      identity.setUsername(preferredUsername);

      if (getConfig().isStoreToken()) {
        identity.setToken(response);
      }

      return identity;
    } catch (Exception e) {
      throw new IdentityBrokerException("Could not fetch attributes from userinfo endpoint.", e);
    }
  }
Beispiel #17
0
  @Test
  public void testUpdateThoroughly() throws IOException {

    FileConfigHandler handler = initCustomConfigFile();

    try (TempFileResource configFile = new TempFileResource(handler.getConfigFile())) {

      final String realm = "test";

      loginAsUser(configFile.getFile(), serverUrl, realm, "user1", "userpass");

      // create an object so we can update it
      KcRegExec exe =
          execute("create --config '" + configFile.getName() + "' -o -s clientId=my_client");

      assertExitCodeAndStdErrSize(exe, 0, 0);

      ClientRepresentation client =
          JsonSerialization.readValue(exe.stdout(), ClientRepresentation.class);

      Assert.assertEquals("enabled", true, client.isEnabled());
      Assert.assertEquals("publicClient", false, client.isPublicClient());
      Assert.assertEquals("bearerOnly", false, client.isBearerOnly());
      Assert.assertTrue("redirectUris is empty", client.getRedirectUris().isEmpty());

      // Merge update
      exe =
          execute(
              "update my_client --config '"
                  + configFile.getName()
                  + "' -o "
                  + " -s enabled=false -s 'redirectUris=[\"http://localhost:8980/myapp/*\"]'");

      assertExitCodeAndStdErrSize(exe, 0, 0);

      client = JsonSerialization.readValue(exe.stdout(), ClientRepresentation.class);
      Assert.assertEquals("enabled", false, client.isEnabled());
      Assert.assertEquals(
          "redirectUris", Arrays.asList("http://localhost:8980/myapp/*"), client.getRedirectUris());

      // Another merge update - test deleting an attribute, deleting a list item and adding a list
      // item
      exe =
          execute(
              "update my_client --config '"
                  + configFile.getName()
                  + "' -o -d redirectUris -s webOrigins+=http://localhost:8980/myapp -s webOrigins+=http://localhost:8981/myapp -d webOrigins[0]");

      assertExitCodeAndStdErrSize(exe, 0, 0);

      client = JsonSerialization.readValue(exe.stdout(), ClientRepresentation.class);

      Assert.assertTrue("redirectUris is empty", client.getRedirectUris().isEmpty());
      Assert.assertEquals(
          "webOrigins", Arrays.asList("http://localhost:8981/myapp"), client.getWebOrigins());

      // Another merge update - test nested attributes and setting an attribute using json format
      // TODO KEYCLOAK-3705 Updating protocolMapper config via client registration endpoint has no
      // effect
      /*
      exe = execute("update my_client --config '" + configFile.getName() + "' -o -s 'protocolMappers[0].config.\"id.token.claim\"=false' " +
              "-s 'protocolMappers[4].config={\"single\": \"true\", \"attribute.nameformat\": \"Basic\", \"attribute.name\": \"Role\"}'");

      assertExitCodeAndStdErrSize(exe, 0, 0);

      client = JsonSerialization.readValue(exe.stdout(), ClientRepresentation.class);
      Assert.assertEquals("protocolMapper[0].config.\"id.token.claim\"", "false", client.getProtocolMappers().get(0).getConfig().get("id.token.claim"));
      Assert.assertEquals("protocolMappers[4].config.single", "true", client.getProtocolMappers().get(4).getConfig().get("single"));
      Assert.assertEquals("protocolMappers[4].config.\"attribute.nameformat\"", "Basic", client.getProtocolMappers().get(4).getConfig().get("attribute.nameformat"));
      Assert.assertEquals("protocolMappers[4].config.\"attribute.name\"", "Role", client.getProtocolMappers().get(4).getConfig().get("attribute.name"));
      */

      // update using oidc format

      // check that using an invalid attribute key is not ignored
      exe = execute("update my_client --nonexisting --config '" + configFile.getName() + "'");

      assertExitCodeAndStreamSizes(exe, 1, 0, 2);
      Assert.assertEquals(
          "error message", "Unsupported option: --nonexisting", exe.stderrLines().get(0));
      Assert.assertEquals(
          "try help",
          "Try '" + CMD + " help update' for more information",
          exe.stderrLines().get(1));

      // try use incompatible endpoint
      exe =
          execute(
              "update my_client --config '"
                  + configFile.getName()
                  + "' -o -s enabled=true -e oidc");

      assertExitCodeAndStreamSizes(exe, 1, 0, 1);
      Assert.assertEquals(
          "error message",
          "Failed to set attribute 'enabled' on document type 'oidc'",
          exe.stderrLines().get(0));

      // test overwrite from file
      exe =
          KcRegExec.newBuilder()
              .argsLine(
                  "update my_client --config '"
                      + configFile.getName()
                      + "' -o  -s clientId=my_client -s 'redirectUris=[\"http://localhost:8980/myapp/*\"]' -f -")
              .stdin(new ByteArrayInputStream("{ \"enabled\": false }".getBytes()))
              .execute();

      assertExitCodeAndStdErrSize(exe, 0, 0);

      client = JsonSerialization.readValue(exe.stdout(), ClientRepresentation.class);
      // web origin is not sent to the server, thus it retains the current value
      Assert.assertEquals(
          "webOrigins", Arrays.asList("http://localhost:8981/myapp"), client.getWebOrigins());
      Assert.assertFalse("enabled is false", client.isEnabled());
      Assert.assertEquals(
          "redirectUris", Arrays.asList("http://localhost:8980/myapp/*"), client.getRedirectUris());

      // test using merge with file
      exe =
          KcRegExec.newBuilder()
              .argsLine(
                  "update my_client --config '"
                      + configFile.getName()
                      + "' -o -s enabled=true -m -f -")
              .stdin(
                  new ByteArrayInputStream(
                      "{ \"webOrigins\": [\"http://localhost:8980/myapp\"] }".getBytes()))
              .execute();

      assertExitCodeAndStdErrSize(exe, 0, 0);

      client = JsonSerialization.readValue(exe.stdout(), ClientRepresentation.class);
      Assert.assertEquals(
          "webOrigins", Arrays.asList("http://localhost:8980/myapp"), client.getWebOrigins());
      Assert.assertTrue("enabled is true", client.isEnabled());
      Assert.assertEquals(
          "redirectUris", Arrays.asList("http://localhost:8980/myapp/*"), client.getRedirectUris());

      // remove registration access token
      exe =
          execute(
              "config registration-token --config '"
                  + configFile.getName()
                  + "' --server "
                  + serverUrl
                  + " --realm "
                  + realm
                  + " --client my_client -d");

      assertExitCodeAndStdErrSize(exe, 0, 0);

      Assert.assertNull(
          "my_client registration token",
          handler
              .loadConfig()
              .ensureRealmConfigData(serverUrl, realm)
              .getClients()
              .get("my_client"));
    }
  }