[KEYCLOAK-4778] Fix for Oracle null value when having an empty String as attribute value (#4406)
* Add client.name as a second parameter to the title expressions in login template * Fixing tooltip. * pt_BR localization for admin screens. * Reverting login.ftl * Added all tooltip messages - even the ones not translated. Translated around 150 messages todas. * More translations. * Fixing wrong edit. * [KEYCLOAK-4778] Null check on Attribute value. This value can be null when retrieved from an Oracle database. * [KEYCLOAK-4778] Create unit tests for empty and null values. * [KEYCLOAK-4778] Move empty and null attributes tests to a separated test method; change tests to empty or null Strings. * [KEYCLOAK-4778] Check if value is null and set it as empty array. In the former code if null was received it would generate an array with 1 string element ["null"]. Also if we set value as null instead of ArrayList, later when the rest call is executed it will generate the same incorrect array again. * [KEYCLOAK-4778] Tests clean up.
This commit is contained in:
parent
924b4f651a
commit
e055589448
3 changed files with 60 additions and 3 deletions
|
@ -23,6 +23,7 @@ import org.keycloak.json.StringListMapDeserializer;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -157,7 +158,7 @@ public class UserRepresentation {
|
||||||
|
|
||||||
public UserRepresentation singleAttribute(String name, String value) {
|
public UserRepresentation singleAttribute(String name, String value) {
|
||||||
if (this.attributes == null) attributes = new HashMap<>();
|
if (this.attributes == null) attributes = new HashMap<>();
|
||||||
attributes.put(name, Arrays.asList(value));
|
attributes.put(name, (value == null ? new ArrayList<String>() : Arrays.asList(value)));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ public class OIDCAttributeMapperHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object convertToType(String type, Object attributeValue) {
|
private static Object convertToType(String type, Object attributeValue) {
|
||||||
if (type == null) return attributeValue;
|
if (type == null || attributeValue == null) return attributeValue;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "boolean":
|
case "boolean":
|
||||||
Boolean booleanObject = getBoolean(attributeValue);
|
Boolean booleanObject = getBoolean(attributeValue);
|
||||||
|
|
|
@ -52,6 +52,7 @@ import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
import static org.hamcrest.Matchers.hasItems;
|
import static org.hamcrest.Matchers.hasItems;
|
||||||
import static org.hamcrest.Matchers.instanceOf;
|
import static org.hamcrest.Matchers.instanceOf;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.hamcrest.Matchers.isEmptyString;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
|
@ -123,7 +124,6 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
||||||
user.singleAttribute("formatted", "6 Foo Street");
|
user.singleAttribute("formatted", "6 Foo Street");
|
||||||
user.singleAttribute("phone", "617-777-6666");
|
user.singleAttribute("phone", "617-777-6666");
|
||||||
|
|
||||||
|
|
||||||
List<String> departments = Arrays.asList("finance", "development");
|
List<String> departments = Arrays.asList("finance", "development");
|
||||||
user.getAttributes().put("departments", departments);
|
user.getAttributes().put("departments", departments);
|
||||||
userResource.update(user);
|
userResource.update(user);
|
||||||
|
@ -242,6 +242,62 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
||||||
events.clear();
|
events.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNullOrEmptyTokenMapping() throws Exception {
|
||||||
|
{
|
||||||
|
UserResource userResource = findUserByUsernameId(adminClient.realm("test"), "test-user@localhost");
|
||||||
|
UserRepresentation user = userResource.toRepresentation();
|
||||||
|
|
||||||
|
user.singleAttribute("empty", "");
|
||||||
|
user.singleAttribute("null", null);
|
||||||
|
userResource.update(user);
|
||||||
|
|
||||||
|
ClientResource app = findClientResourceByClientId(adminClient.realm("test"), "test-app");
|
||||||
|
app.getProtocolMappers().createMapper(createClaimMapper("empty", "empty", "empty", "String", true, "", true, true, false)).close();
|
||||||
|
app.getProtocolMappers().createMapper(createClaimMapper("null", "null", "null", "String", true, "", true, true, false)).close();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
OAuthClient.AccessTokenResponse response = browserLogin("password", "test-user@localhost", "password");
|
||||||
|
|
||||||
|
IDToken idToken = oauth.verifyIDToken(response.getIdToken());
|
||||||
|
Object empty = idToken.getOtherClaims().get("empty");
|
||||||
|
assertThat((empty == null ? null : (String) empty), isEmptyString());
|
||||||
|
Object nulll = idToken.getOtherClaims().get("null");
|
||||||
|
assertNull(nulll);
|
||||||
|
|
||||||
|
AccessToken accessToken = oauth.verifyToken(response.getAccessToken());
|
||||||
|
oauth.openLogout();
|
||||||
|
}
|
||||||
|
|
||||||
|
// undo mappers
|
||||||
|
{
|
||||||
|
ClientResource app = findClientByClientId(adminClient.realm("test"), "test-app");
|
||||||
|
ClientRepresentation clientRepresentation = app.toRepresentation();
|
||||||
|
for (ProtocolMapperRepresentation model : clientRepresentation.getProtocolMappers()) {
|
||||||
|
if (model.getName().equals("empty")
|
||||||
|
|| model.getName().equals("null")
|
||||||
|
) {
|
||||||
|
app.getProtocolMappers().delete(model.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
events.clear();
|
||||||
|
|
||||||
|
{
|
||||||
|
OAuthClient.AccessTokenResponse response = browserLogin("password", "test-user@localhost", "password");
|
||||||
|
IDToken idToken = oauth.verifyIDToken(response.getIdToken());
|
||||||
|
assertNull(idToken.getAddress());
|
||||||
|
assertNull(idToken.getOtherClaims().get("empty"));
|
||||||
|
assertNull(idToken.getOtherClaims().get("null"));
|
||||||
|
|
||||||
|
oauth.openLogout();
|
||||||
|
}
|
||||||
|
events.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUserRoleToAttributeMappers() throws Exception {
|
public void testUserRoleToAttributeMappers() throws Exception {
|
||||||
|
|
Loading…
Reference in a new issue