From 30e4a98e7fb221052d70efc9bdeb80dc77bd1667 Mon Sep 17 00:00:00 2001 From: Iwan Igonin Date: Thu, 22 Jan 2026 17:58:14 +0100 Subject: [PATCH] fix authToken Signed-off-by: Igonin Co-authored-by: Benny Goerzig Co-authored-by: Karsten Schnitter Co-authored-by: Kai Sternad --- .../dlic/rest/api/InternalUsersApiAction.java | 2 + .../securityconf/impl/v7/InternalUserV7.java | 4 +- .../opensearch/security/user/UserService.java | 45 ++++++++++--------- 3 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java index f0eeb89926..b16feaeda5 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java @@ -338,6 +338,8 @@ public Map allowedKeys() { .put("opendistro_security_roles", DataType.ARRAY) .put("hash", DataType.STRING) .put("password", DataType.STRING) + .put("service", DataType.BOOLEAN) + .put("enabled", DataType.BOOLEAN) .build(); } }); diff --git a/src/main/java/org/opensearch/security/securityconf/impl/v7/InternalUserV7.java b/src/main/java/org/opensearch/security/securityconf/impl/v7/InternalUserV7.java index cf8212b92f..501deb35aa 100644 --- a/src/main/java/org/opensearch/security/securityconf/impl/v7/InternalUserV7.java +++ b/src/main/java/org/opensearch/security/securityconf/impl/v7/InternalUserV7.java @@ -127,11 +127,11 @@ public void setAttributes(Map attributes) { this.attributes = attributes; } - public boolean enabled() { + public boolean isEnabled() { return this.enabled; } - public boolean service() { + public boolean isService() { return this.service; } diff --git a/src/main/java/org/opensearch/security/user/UserService.java b/src/main/java/org/opensearch/security/user/UserService.java index d2289100f0..5b1d7c828b 100644 --- a/src/main/java/org/opensearch/security/user/UserService.java +++ b/src/main/java/org/opensearch/security/user/UserService.java @@ -155,18 +155,24 @@ public SecurityDynamicConfiguration createOrUpdateAccount(ObjectNode contentA throw new UserServiceException(NO_ACCOUNT_NAME_MESSAGE); } - SecurityJsonNode attributeNode = securityJsonNode.get("attributes"); + // Read service flag from top level (boolean) + SecurityJsonNode serviceNode = securityJsonNode.get("service"); + boolean isServiceAccount = !serviceNode.isNull() && Boolean.parseBoolean(serviceNode.asString()); - if (!attributeNode.get("service").isNull() && attributeNode.get("service").asString().equalsIgnoreCase("true")) { // If this is a - // service account + if (isServiceAccount) { verifyServiceAccount(securityJsonNode, accountName); String password = generatePassword(); contentAsNode.put("hash", passwordHasher.hash(password.toCharArray())); - contentAsNode.put("service", "true"); + contentAsNode.put("service", true); } else { - contentAsNode.put("service", "false"); + contentAsNode.put("service", false); } + // Read enabled flag from top level (boolean), default to true + SecurityJsonNode enabledNode = securityJsonNode.get("enabled"); + boolean isEnabled = enabledNode.isNull() || Boolean.parseBoolean(enabledNode.asString()); + contentAsNode.put("enabled", isEnabled); + securityJsonNode = new SecurityJsonNode(contentAsNode); final var foundRestrictedContents = restrictedFromUsername(accountName); if (foundRestrictedContents.isPresent()) { @@ -185,10 +191,6 @@ public SecurityDynamicConfiguration createOrUpdateAccount(ObjectNode contentA contentAsNode.remove("password"); } - if (!attributeNode.get("enabled").isNull()) { - contentAsNode.put("enabled", securityJsonNode.get("enabled").asString()); - } - final boolean userExisted = internalUsersConfiguration.exists(accountName); // sanity checks, hash is mandatory for newly created users @@ -273,21 +275,23 @@ public AuthToken generateAuthToken(String accountName) throws IOException { final ObjectNode contentAsNode = (ObjectNode) accountDetails; SecurityJsonNode securityJsonNode = new SecurityJsonNode(contentAsNode); - Optional.ofNullable(securityJsonNode.get("attributes").get("service")) - .map(SecurityJsonNode::asString) - .filter("true"::equalsIgnoreCase) - .orElseThrow(() -> new UserServiceException(AUTH_TOKEN_GENERATION_MESSAGE)); + var serviceNode = securityJsonNode.get("service"); + boolean isService = !serviceNode.isNull() && Boolean.parseBoolean(serviceNode.asString()); + if (!isService) { + throw new UserServiceException(AUTH_TOKEN_GENERATION_MESSAGE); + } - Optional.ofNullable(securityJsonNode.get("attributes").get("enabled")) - .map(SecurityJsonNode::asString) - .filter("true"::equalsIgnoreCase) - .orElseThrow(() -> new UserServiceException(AUTH_TOKEN_GENERATION_MESSAGE)); + var enabledNode = securityJsonNode.get("enabled"); + boolean isEnabled = enabledNode.isNull() || Boolean.parseBoolean(enabledNode.asString()); + if (!isEnabled) { + throw new UserServiceException(AUTH_TOKEN_GENERATION_MESSAGE); + } // Generate a new password for the account and store the hash of it String plainTextPassword = generatePassword(); contentAsNode.put("hash", passwordHasher.hash(plainTextPassword.toCharArray())); - contentAsNode.put("enabled", "true"); - contentAsNode.put("service", "true"); + contentAsNode.put("enabled", true); + contentAsNode.put("service", true); // Update the internal user associated with the auth token internalUsersConfiguration.remove(accountName); @@ -296,7 +300,8 @@ public AuthToken generateAuthToken(String accountName) throws IOException { accountName, DefaultObjectMapper.readTree(contentAsNode, internalUsersConfiguration.getImplementingClass()) ); - saveAndUpdateConfigs(getUserConfigName().toString(), client, CType.INTERNALUSERS, internalUsersConfiguration); + saveAndUpdateConfigs(securityIndex, client, CType.INTERNALUSERS, internalUsersConfiguration); + configurationRepository.reloadConfiguration(java.util.Set.of(CType.INTERNALUSERS), null); authToken = Base64.getUrlEncoder().encodeToString((accountName + ":" + plainTextPassword).getBytes(StandardCharsets.UTF_8)); return new BasicAuthToken("Basic " + authToken);