/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.models.jpa;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.credential.CredentialModel;
import org.keycloak.credential.UserCredentialStore;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.jpa.entities.CredentialAttributeEntity;
import org.keycloak.models.jpa.entities.CredentialEntity;
import org.keycloak.models.jpa.entities.UserEntity;
import org.keycloak.models.utils.KeycloakModelUtils;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class JpaUserCredentialStore implements UserCredentialStore {
private final KeycloakSession session;
protected final EntityManager em;
public JpaUserCredentialStore(KeycloakSession session, EntityManager em) {
this.session = session;
this.em = em;
}
@Override
public void updateCredential(RealmModel realm, UserModel user, CredentialModel cred) {
CredentialEntity entity = em.find(CredentialEntity.class, cred.getId());
if (entity == null) return;
entity.setAlgorithm(cred.getAlgorithm());
entity.setCounter(cred.getCounter());
entity.setCreatedDate(cred.getCreatedDate());
entity.setDevice(cred.getDevice());
entity.setDigits(cred.getDigits());
entity.setHashIterations(cred.getHashIterations());
entity.setPeriod(cred.getPeriod());
entity.setSalt(cred.getSalt());
entity.setType(cred.getType());
entity.setValue(cred.getValue());
if (entity.getCredentialAttributes().isEmpty() && (cred.getConfig() == null || cred.getConfig().isEmpty())) {
} else {
MultivaluedHashMap<String, String> attrs = cred.getConfig();
MultivaluedHashMap<String, String> config = cred.getConfig();
if (config == null) config = new MultivaluedHashMap<>();
Iterator<CredentialAttributeEntity> it = entity.getCredentialAttributes().iterator();
while (it.hasNext()) {
CredentialAttributeEntity attr = it.next();
List<String> values = config.getList(attr.getName());
if (values == null || !values.contains(attr.getValue())) {
em.remove(attr);
it.remove();
} else {
attrs.add(attr.getName(), attr.getValue());
}
}
for (String key : config.keySet()) {
List<String> values = config.getList(key);
List<String> attrValues = attrs.getList(key);
for (String val : values) {
if (attrValues == null || !attrValues.contains(val)) {
CredentialAttributeEntity attr = new CredentialAttributeEntity();
attr.setId(KeycloakModelUtils.generateId());
attr.setValue(val);
attr.setName(key);
attr.setCredential(entity);
em.persist(attr);
entity.getCredentialAttributes().add(attr);
}
}
}
}
}
@Override
public CredentialModel createCredential(RealmModel realm, UserModel user, CredentialModel cred) {
CredentialEntity entity = new CredentialEntity();
String id = cred.getId() == null ? KeycloakModelUtils.generateId() : cred.getId();
entity.setId(id);
entity.setAlgorithm(cred.getAlgorithm());
entity.setCounter(cred.getCounter());
entity.setCreatedDate(cred.getCreatedDate());
entity.setDevice(cred.getDevice());
entity.setDigits(cred.getDigits());
entity.setHashIterations(cred.getHashIterations());
entity.setPeriod(cred.getPeriod());
entity.setSalt(cred.getSalt());
entity.setType(cred.getType());
entity.setValue(cred.getValue());
UserEntity userRef = em.getReference(UserEntity.class, user.getId());
entity.setUser(userRef);
em.persist(entity);
MultivaluedHashMap<String, String> config = cred.getConfig();
if (config != null && !config.isEmpty()) {
for (String key : config.keySet()) {
List<String> values = config.getList(key);
for (String val : values) {
CredentialAttributeEntity attr = new CredentialAttributeEntity();
attr.setId(KeycloakModelUtils.generateId());
attr.setValue(val);
attr.setName(key);
attr.setCredential(entity);
em.persist(attr);
entity.getCredentialAttributes().add(attr);
}
}
}
return toModel(entity);
}
@Override
public boolean removeStoredCredential(RealmModel realm, UserModel user, String id) {
CredentialEntity entity = em.find(CredentialEntity.class, id);
if (entity == null) return false;
em.remove(entity);
return true;
}
@Override
public CredentialModel getStoredCredentialById(RealmModel realm, UserModel user, String id) {
CredentialEntity entity = em.find(CredentialEntity.class, id);
if (entity == null) return null;
CredentialModel model = toModel(entity);
return model;
}
protected CredentialModel toModel(CredentialEntity entity) {
CredentialModel model = new CredentialModel();
model.setId(entity.getId());
model.setType(entity.getType());
model.setValue(entity.getValue());
model.setAlgorithm(entity.getAlgorithm());
model.setSalt(entity.getSalt());
model.setPeriod(entity.getPeriod());
model.setCounter(entity.getCounter());
model.setCreatedDate(entity.getCreatedDate());
model.setDevice(entity.getDevice());
model.setDigits(entity.getDigits());
MultivaluedHashMap<String, String> config = new MultivaluedHashMap<>();
model.setConfig(config);
for (CredentialAttributeEntity attr : entity.getCredentialAttributes()) {
config.add(attr.getName(), attr.getValue());
}
return model;
}
@Override
public List<CredentialModel> getStoredCredentials(RealmModel realm, UserModel user) {
UserEntity userEntity = em.getReference(UserEntity.class, user.getId());
TypedQuery<CredentialEntity> query = em.createNamedQuery("credentialByUser", CredentialEntity.class)
.setParameter("user", userEntity);
List<CredentialEntity> results = query.getResultList();
List<CredentialModel> rtn = new LinkedList<>();
for (CredentialEntity entity : results) {
rtn.add(toModel(entity));
}
return rtn;
}
@Override
public List<CredentialModel> getStoredCredentialsByType(RealmModel realm, UserModel user, String type) {
UserEntity userEntity = em.getReference(UserEntity.class, user.getId());
TypedQuery<CredentialEntity> query = em.createNamedQuery("credentialByUserAndType", CredentialEntity.class)
.setParameter("type", type)
.setParameter("user", userEntity);
List<CredentialEntity> results = query.getResultList();
List<CredentialModel> rtn = new LinkedList<>();
for (CredentialEntity entity : results) {
rtn.add(toModel(entity));
}
return rtn;
}
@Override
public CredentialModel getStoredCredentialByNameAndType(RealmModel realm, UserModel user, String name, String type) {
UserEntity userEntity = em.getReference(UserEntity.class, user.getId());
TypedQuery<CredentialEntity> query = em.createNamedQuery("credentialByNameAndType", CredentialEntity.class)
.setParameter("type", type)
.setParameter("device", name)
.setParameter("user", userEntity);
List<CredentialEntity> results = query.getResultList();
if (results.isEmpty()) return null;
return toModel(results.get(0));
}
@Override
public void close() {
}
}