[keycloak-user] Not existent attributes for users from user-federeation cause NPE

Lorenzo Luconi Trombacchi lorenzo.luconi at iit.cnr.it
Mon Feb 4 03:57:52 EST 2019


Hello Dmitry,

thank you for your reply.
I developed my keycloak spi based on keycloak-quickstarts/user-storage-jpa, but this project is two years old. The getAttribute in this project looks like my implementation:

https://github.com/keycloak/keycloak-quickstarts/blob/3b739ff053a2ee024a2a01dd207bf638962a93f6/user-storage-jpa/src/main/java/org/keycloak/quickstart/storage/user/UserAdapter.java#L126

@Override
    public List<String> getAttribute(String name) {
        if (name.equals("phone")) {
            List<String> phone = new LinkedList<>();
            phone.add(entity.getPhone());
            return phone;
        } else {
            return super.getAttribute(name);
        }
    }

In case of a missing attribute this method returns a null value and then a Null Pointer Exception is thrown. I think the keycloak code should be fixed to avoid NPE or at least the example should be changed. Anyway this works for me:


@Override
public List<String> getAttribute(String name) {
    final List<String> values;
    if (attributes.containsKey(name)) {
        values = attributes.get(name);
    } else {
        values = super.getAttribute(name);
    }

    return Optional.ofNullable(values).orElse(Collections.emptyList());
}

Thanks,
Lorenzo


> Il giorno 1 feb 2019, alle ore 19:10, Dmitry Telegin <dt at acutus.pro> ha scritto:
> 
> Hello Lorenzo,
> 
> Out of interest I've tried to play with keycloak-quickstarts/user-storage-simple. I was able to authenticate as "tbrady" even though its UserModel obviously returns null from getAttribute(). But in this case KeycloakModelUtils::resolveAttribute() is invoked not on the UserModel supplied by the provider, but rather on o.k.models.cache.infinispan.UserAdapter wrapper (which performs null checking and returns an empty list in that case). Not sure why resolveAttribute is invoked on your UserAdapter directly, but I think it's safe to return an empty list too.
> 
> Did you try keycloak-quickstarts/user-storage-jpa by the way?
> 
> Cheers,
> Dmitry Telegin
> CTO, Acutus s.r.o.
> Keycloak Consulting and Training
> 
> Pod lipami street 339/52, 130 00 Prague 3, Czech Republic
> +42 (022) 888-30-71
> E-mail: info at acutus.pro
> 
> On Fri, 2019-02-01 at 16:54 +0100, Lorenzo Luconi Trombacchi wrote:
>> I’m using Keycloak version 4.8.3 with a custom user federation plugin. I created a new realm, configured my user federation plugin and created a new client. I tried to authenticate and I got an error 500 from keycloak.
>> In Keycloak log I found this NullPointerException:
>> 
>> 14:09:15,472 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (default task-1) Uncaught server error: java.lang.NullPointerException
>>>  	at org.keycloak.models.utils.KeycloakModelUtils.resolveAttribute(KeycloakModelUtils.java:414)
>>>  	at org.keycloak.models.utils.KeycloakModelUtils.resolveAttribute(KeycloakModelUtils.java:415)
>>>  	at org.keycloak.protocol.oidc.mappers.UserAttributeMapper.setClaim(UserAttributeMapper.java:93)
>>>  	at org.keycloak.protocol.oidc.mappers.UserAttributeMapper.setClaim(UserAttributeMapper.java:101)
>>>  	at org.keycloak.protocol.oidc.mappers.AbstractOIDCProtocolMapper.setClaim(AbstractOIDCProtocolMapper.java:117)
>>>  	at org.keycloak.protocol.oidc.mappers.AbstractOIDCProtocolMapper.setClaim(AbstractOIDCProtocolMapper.java:119)
>>>  	at org.keycloak.protocol.oidc.mappers.AbstractOIDCProtocolMapper.transformAccessToken(AbstractOIDCProtocolMapper.java:81)
>>>  	at org.keycloak.protocol.oidc.TokenManager.transformAccessToken(TokenManager.java:606)
>>>  	at org.keycloak.protocol.oidc.mappers.AbstractOIDCProtocolMapper.transformAccessToken(AbstractOIDCProtocolMapper.java:81)
>>>  	at org.keycloak.protocol.oidc.TokenManager.createClientAccessToken(TokenManager.java:422)
>>>  	at org.keycloak.protocol.oidc.TokenManager$AccessTokenResponseBuilder.generateAccessToken(TokenManager.java:795)
>>>  	at org.keycloak.protocol.oidc.TokenManager.transformAccessToken(TokenManager.java:544)
>>>  	at org.keycloak.protocol.oidc.endpoints.TokenEndpoint.resourceOwnerPasswordCredentialsGrant(TokenEndpoint.java:569)
>>>  	at org.keycloak.protocol.oidc.endpoints.TokenEndpoint.processGrantRequest(TokenEndpoint.java:186)
>>>  	at org.keycloak.protocol.oidc.TokenManager.createClientAccessToken(TokenManager.java:402)
>> …..
>> 
>> After some tests I found the problem: the “Assigned Default Client Scopes” list, in my newly created client, includes the “profile” scope. 
>> The “profile” scope includes a lot of attributes and not all of them are exported from my federation plugin for my users. Removing profile scope solve the problem and now I can successfully authenticate my federeted users.
>> 
>> In class KeycloakModelUtils  the are two implementation of the method resolveAttribute:
>> 
>>     public static List<String>  resolveAttribute(GroupModel group, String name) {
>>         List<String> values = group.getAttribute(name);
>>         if (values != null && !values.isEmpty()) return values;
>>         if (group.getParentId() == null) return null;
>>         return resolveAttribute(group.getParent(), name);
>> 
>>     }
>> 
>> 
>>     public static Collection<String> resolveAttribute(UserModel user, String name, boolean aggregateAttrs) {
>>         List<String> values = user.getAttribute(name);
>>         Set<String> aggrValues = new HashSet<String>();
>>         if (!values.isEmpty()) {
>>             if (!aggregateAttrs) {
>>                 return values;
>>             }
>>             aggrValues.addAll(values);
>>         }
>>         for (GroupModel group : user.getGroups()) {
>>             values = resolveAttribute(group, name);
>>             if (values != null && !values.isEmpty()) {
>>                 if (!aggregateAttrs) {
>>                     return values;
>>                 }
>>                 aggrValues.addAll(values);
>>             }
>>         }
>>         return aggrValues;
>>     }
>> 
>> 
>> As you can see the first implementation checks if values is null, but not the second one where I got NPE.
>> 
>> In my UserModel implementation I override the getAttrubute method:
>> 
>> public class UserAdapter extends AbstractUserAdapterFederatedStorage {
>> 
>> …..
>>     @Override
>>     public List<String> getAttribute(String name) {
>>         if (attributes.containsKey(name)) {
>>             return attributes.get(name);
>>         }
>> 
>>         return super.getAttribute(name);
>>     }
>> 
>> }
>> 
>> 
>> If I force this method to return an empty list instead of null value, this solve the problem. Is this the right fix? getAttribute method must not returns a null value?
>> 
>> 
>> I hope this helps.
>> 
>> Thanks,
>> Lorenzo
>> 
>> 
>> 
>> 
>> 
>> _______________________________________________
>> keycloak-user mailing list
>> keycloak-user at lists.jboss.org
>> https://lists.jboss.org/mailman/listinfo/keycloak-user




More information about the keycloak-user mailing list