package org.keycloak.models.mongo.keycloak.adapters;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.mongo.api.NoSQL;
import org.keycloak.models.mongo.api.query.NoSQLQuery;
import org.keycloak.models.mongo.keycloak.data.ApplicationData;
import org.keycloak.models.mongo.keycloak.data.RoleData;
import org.keycloak.models.mongo.keycloak.data.UserData;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class ApplicationAdapter implements ApplicationModel {
private final ApplicationData application;
private final NoSQL noSQL;
private UserData resourceUser;
public ApplicationAdapter(ApplicationData applicationData, NoSQL noSQL) {
this.application = applicationData;
this.noSQL = noSQL;
}
@Override
public void updateApplication() {
noSQL.saveObject(application);
}
@Override
public UserModel getApplicationUser() {
// This is not thread-safe. Assumption is that ApplicationAdapter instance is per-client object
if (resourceUser == null) {
resourceUser = noSQL.loadObject(UserData.class, application.getResourceUserId());
}
return resourceUser != null ? new UserAdapter(resourceUser, noSQL) : null;
}
@Override
public String getId() {
return application.getId();
}
@Override
public String getName() {
return application.getName();
}
@Override
public void setName(String name) {
application.setName(name);
}
@Override
public boolean isEnabled() {
return application.isEnabled();
}
@Override
public void setEnabled(boolean enabled) {
application.setEnabled(enabled);
}
@Override
public boolean isSurrogateAuthRequired() {
return application.isSurrogateAuthRequired();
}
@Override
public void setSurrogateAuthRequired(boolean surrogateAuthRequired) {
application.setSurrogateAuthRequired(surrogateAuthRequired);
}
@Override
public String getManagementUrl() {
return application.getManagementUrl();
}
@Override
public void setManagementUrl(String url) {
application.setManagementUrl(url);
}
@Override
public void setBaseUrl(String url) {
application.setBaseUrl(url);
}
@Override
public String getBaseUrl() {
return application.getBaseUrl();
}
@Override
public RoleAdapter getRole(String name) {
NoSQLQuery query = noSQL.createQueryBuilder()
.andCondition("name", name)
.andCondition("applicationId", getId())
.build();
RoleData role = noSQL.loadSingleObject(RoleData.class, query);
if (role == null) {
return null;
} else {
return new RoleAdapter(role, noSQL);
}
}
@Override
public RoleModel getRoleById(String id) {
RoleData role = noSQL.loadObject(RoleData.class, id);
if (role == null) {
return null;
} else {
return new RoleAdapter(role, noSQL);
}
}
@Override
public void grantRole(UserModel user, RoleModel role) {
UserData userData = ((UserAdapter)user).getUser();
noSQL.pushItemToList(userData, "roleIds", role.getId());
}
@Override
public RoleAdapter addRole(String name) {
if (getRole(name) != null) {
throw new IllegalArgumentException("Role " + name + " already exists");
}
RoleData roleData = new RoleData();
roleData.setName(name);
roleData.setApplicationId(getId());
noSQL.saveObject(roleData);
return new RoleAdapter(roleData, noSQL);
}
@Override
public List<RoleModel> getRoles() {
NoSQLQuery query = noSQL.createQueryBuilder()
.andCondition("applicationId", getId())
.build();
List<RoleData> roles = noSQL.loadObjects(RoleData.class, query);
List<RoleModel> result = new ArrayList<RoleModel>();
for (RoleData role : roles) {
result.add(new RoleAdapter(role, noSQL));
}
return result;
}
// Static so that it can be used from RealmAdapter as well
static List<RoleData> getAllRolesOfUser(UserModel user, NoSQL noSQL) {
UserData userData = ((UserAdapter)user).getUser();
List<String> roleIds = userData.getRoleIds();
NoSQLQuery query = noSQL.createQueryBuilder()
.inCondition("_id", roleIds)
.build();
return noSQL.loadObjects(RoleData.class, query);
}
@Override
public Set<String> getRoleMappingValues(UserModel user) {
Set<String> result = new HashSet<String>();
List<RoleData> roles = getAllRolesOfUser(user, noSQL);
// TODO: Maybe improve as currently we need to obtain all roles and then filter programmatically...
for (RoleData role : roles) {
if (getId().equals(role.getApplicationId())) {
result.add(role.getName());
}
}
return result;
}
@Override
public List<RoleModel> getRoleMappings(UserModel user) {
List<RoleModel> result = new ArrayList<RoleModel>();
List<RoleData> roles = getAllRolesOfUser(user, noSQL);
// TODO: Maybe improve as currently we need to obtain all roles and then filter programmatically...
for (RoleData role : roles) {
if (getId().equals(role.getApplicationId())) {
result.add(new RoleAdapter(role, noSQL));
}
}
return result;
}
@Override
public void deleteRoleMapping(UserModel user, RoleModel role) {
UserData userData = ((UserAdapter)user).getUser();
noSQL.pullItemFromList(userData, "roleIds", role.getId());
}
@Override
public void addScopeMapping(UserModel agent, String roleName) {
RoleAdapter role = getRole(roleName);
if (role == null) {
throw new RuntimeException("Role not found");
}
addScopeMapping(agent, role);
}
@Override
public void addScopeMapping(UserModel agent, RoleModel role) {
UserData userData = ((UserAdapter)agent).getUser();
noSQL.pushItemToList(userData, "scopeIds", role.getId());
}
@Override
public Set<String> getScopeMapping(UserModel agent) {
UserData userData = ((UserAdapter)agent).getUser();
List<String> scopeIds = userData.getScopeIds();
Set<String> result = new HashSet<String>();
NoSQLQuery query = noSQL.createQueryBuilder()
.inCondition("_id", scopeIds)
.build();
List<RoleData> roles = noSQL.loadObjects(RoleData.class, query);
// TODO: Maybe improve as currently we need to obtain all roles and then filter programmatically...
for (RoleData role : roles) {
if (getId().equals(role.getApplicationId())) {
result.add(role.getName());
}
}
return result;
}
}