/*
* oxAuth is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text.
*
* Copyright (c) 2014, Gluu
*/
package org.xdi.oxauth.service.uma;
import com.unboundid.ldap.sdk.Filter;
import com.unboundid.ldap.sdk.LDAPException;
import org.apache.commons.lang.StringUtils;
import org.gluu.site.ldap.persistence.LdapEntryManager;
import org.slf4j.Logger;
import org.xdi.oxauth.model.config.StaticConfiguration;
import org.xdi.oxauth.model.configuration.AppConfiguration;
import org.xdi.oxauth.model.error.ErrorResponseFactory;
import org.xdi.oxauth.model.uma.UmaErrorResponseType;
import org.xdi.oxauth.model.uma.persistence.InternalExternal;
import org.xdi.oxauth.model.uma.persistence.ScopeDescription;
import org.xdi.oxauth.model.uma.persistence.UmaScopeType;
import org.xdi.oxauth.service.InumService;
import org.xdi.oxauth.uma.ws.rs.UmaConfigurationWS;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.inject.Named;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @author Yuriy Zabrovarnyy
* @author Yuriy Movchan
* @version 0.9, 22/04/2013
*/
@Stateless
@Named("umaScopeService")
public class ScopeService {
@Inject
private Logger log;
@Inject
private LdapEntryManager ldapEntryManager;
@Inject
private InumService inumService;
@Inject
private ErrorResponseFactory errorResponseFactory;
@Inject
private AppConfiguration appConfiguration;
@Inject
private StaticConfiguration staticConfiguration;
public List<ScopeDescription> getAllScopes() {
try {
return ldapEntryManager.findEntries(baseDn(), ScopeDescription.class, Filter.createPresenceFilter("inum"));
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return Collections.emptyList();
}
public List<ScopeDescription> getScopes(UmaScopeType p_type) {
try {
if (p_type != null) {
final Filter filter = Filter.create(String.format("&(oxType=%s)", p_type.getValue()));
return ldapEntryManager.findEntries(baseDn(), ScopeDescription.class, filter);
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return Collections.emptyList();
}
public ScopeDescription getInternalScope(String p_scopeId) {
try {
final Filter filter = Filter.create(String.format("&(oxType=%s)(oxId=%s)", UmaScopeType.INTERNAL.getValue(), p_scopeId));
final List<ScopeDescription> entries = ldapEntryManager.findEntries(baseDn(), ScopeDescription.class, filter);
if (entries != null && !entries.isEmpty()) {
// if more then one scope then it's problem, non-deterministic behavior, id must be unique
if (entries.size() > 1) {
log.error("Found more then one internal uma scope by input id: {}" + p_scopeId);
for (ScopeDescription s : entries) {
log.error("Scope, Id: {}, dn: {}", s.getId(), s.getDn());
}
}
return entries.get(0);
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return null;
}
public boolean persist(ScopeDescription p_scopeDescription) {
try {
if (StringUtils.isBlank(p_scopeDescription.getDn())) {
p_scopeDescription.setDn(String.format("inum=%s,%s", p_scopeDescription.getInum(), baseDn()));
}
ldapEntryManager.persist(p_scopeDescription);
return true;
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
public List<String> getScopeDNsByUrlsAndAddToLdapIfNeeded(List<String> scopeUrls) {
final List<String> result = new ArrayList<String>();
if (scopeUrls != null && !scopeUrls.isEmpty()) {
try {
List<String> notInternalScopeUrls = handleInternalScopes(scopeUrls, result);
if (notInternalScopeUrls.size() > 0) {
handleExternalScopes(notInternalScopeUrls, result);
}
} catch (WebApplicationException e) {
throw e;
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
return result;
}
private List<String> handleInternalScopes(List<String> p_scopeUrls, List<String> result) {
List<String> notProcessedScopeUrls = new ArrayList<String>(p_scopeUrls);
try {
final Filter filter = Filter.create(String.format("&(oxType=%s)", InternalExternal.INTERNAL.getValue()));
final List<ScopeDescription> entries = ldapEntryManager.findEntries(baseDn(), ScopeDescription.class, filter);
if (entries != null && !entries.isEmpty()) {
for (String scopeUrl : p_scopeUrls) {
for (ScopeDescription scopeDescription : entries) {
final String internalScopeUrl = getInternalScopeUrl(scopeDescription);
if (internalScopeUrl.equals(scopeUrl) && !result.contains(internalScopeUrl)) {
result.add(scopeDescription.getDn());
notProcessedScopeUrls.remove(scopeUrl);
}
}
}
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return notProcessedScopeUrls;
}
private void handleExternalScopes(List<String> scopeUrls, List<String> result) throws LDAPException {
for (String scopeUrl : scopeUrls) {
final Filter filter = Filter.create(String.format("&(oxUrl=%s)", scopeUrl));
final List<ScopeDescription> entries = ldapEntryManager.findEntries(baseDn(), ScopeDescription.class, filter);
if (entries != null && !entries.isEmpty()) {
result.add(entries.get(0).getDn());
} else { // scope is not in ldap, add it dynamically
final Boolean addAutomatically = appConfiguration.getUmaAddScopesAutomatically();
if (addAutomatically != null && addAutomatically) {
final String inum = inumService.generateInum();
final ScopeDescription newScope = new ScopeDescription();
newScope.setInum(inum);
newScope.setUrl(scopeUrl);
newScope.setDisplayName(scopeUrl); // temp solution : need extract info from scope description on resource server
newScope.setId(UmaScopeType.EXTERNAL_AUTO.getValue()); // dummy id : not sure what to put right now as id is required by @NotNull annotation
newScope.setType(InternalExternal.EXTERNAL_AUTO);
final boolean persisted = persist(newScope);
if (persisted) {
result.add(newScope.getDn());
}
} else {
throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST)
.entity(errorResponseFactory.getUmaJsonErrorResponse(UmaErrorResponseType.INVALID_RESOURCE_SET_SCOPE)).build());
}
}
}
}
public List<ScopeDescription> getScopesByUrls(List<String> p_scopeUrls) {
List<ScopeDescription> scopes = new ArrayList<ScopeDescription>();
try {
// external scopes
Filter filter = createAnyFilterByUrls(p_scopeUrls);
if (filter != null) {
final List<ScopeDescription> entries = ldapEntryManager.findEntries(baseDn(), ScopeDescription.class, filter);
if (entries != null) {
scopes.addAll(entries);
}
}
// internal scopes
filter = Filter.create(String.format("&(oxType=%s)", InternalExternal.INTERNAL.getValue()));
final List<ScopeDescription> entries = ldapEntryManager.findEntries(baseDn(), ScopeDescription.class, filter);
if (entries != null && !entries.isEmpty()) {
for (String scopeUrl : p_scopeUrls) {
for (ScopeDescription scopeDescription : entries) {
final String internalScopeUrl = getInternalScopeUrl(scopeDescription);
if (internalScopeUrl.equals(scopeUrl) && !scopes.contains(internalScopeUrl)) {
scopes.add(scopeDescription);
}
}
}
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return scopes;
}
// TODO: Optimize scopes loading. It's possible to loads all scope in one request.
public List<ScopeDescription> getScopesByDns(List<String> p_scopeDns) {
final List<ScopeDescription> result = new ArrayList<ScopeDescription>();
try {
if (p_scopeDns != null && !p_scopeDns.isEmpty()) {
for (String dn : p_scopeDns) {
final ScopeDescription scopeDescription = ldapEntryManager.find(ScopeDescription.class, dn);
if (scopeDescription != null) {
result.add(scopeDescription);
}
}
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return result;
}
public List<String> getScopeUrlsByDns(List<String> p_scopeDns) {
return getScopeUrls(getScopesByDns(p_scopeDns));
}
public static List<String> getScopeDNs(List<ScopeDescription> p_scopes) {
final List<String> result = new ArrayList<String>();
if (p_scopes != null && !p_scopes.isEmpty()) {
for (ScopeDescription s : p_scopes) {
result.add(s.getDn());
}
}
return result;
}
public List<String> getScopeUrls(List<ScopeDescription> p_scopes) {
final List<String> result = new ArrayList<String>();
if (p_scopes != null && !p_scopes.isEmpty()) {
for (ScopeDescription s : p_scopes) {
final InternalExternal type = s.getType();
if (type != null) {
switch (type) {
case EXTERNAL:
case EXTERNAL_AUTO:
result.add(s.getUrl());
break;
case INTERNAL:
result.add(getInternalScopeUrl(s));
break;
}
} else {
result.add(s.getUrl());
}
}
}
return result;
}
private String getInternalScopeUrl(ScopeDescription internalScope) {
if (internalScope != null && internalScope.getType() == InternalExternal.INTERNAL) {
return getScopeEndpoint() + "/" + internalScope.getId();
}
return "";
}
private String getScopeEndpoint() {
return appConfiguration.getBaseEndpoint() + UmaConfigurationWS.UMA_SCOPES_SUFFIX;
}
private Filter createAnyFilterByUrls(List<String> p_scopeUrls) {
try {
if (p_scopeUrls != null && !p_scopeUrls.isEmpty()) {
final StringBuilder sb = new StringBuilder("(|");
for (String url : p_scopeUrls) {
sb.append("(");
sb.append("oxUrl=");
sb.append(url);
sb.append(")");
}
sb.append(")");
final String filterAsString = sb.toString();
log.trace("Uma scope urls: " + p_scopeUrls + ", ldapFilter: " + filterAsString);
return Filter.create(filterAsString);
}
} catch (LDAPException e) {
log.error(e.getMessage(), e);
}
return null;
}
public String baseDn() {
return String.format("ou=scopes,%s", staticConfiguration.getBaseDn().getUmaBase());
}
}