/**
* Copyright (C) 2010-2017 Structr GmbH
*
* This file is part of Structr <http://structr.org>.
*
* Structr is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Structr is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Structr. If not, see <http://www.gnu.org/licenses/>.
*/
package org.structr.ldap;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import org.apache.directory.server.core.LdapPrincipal;
import org.apache.directory.server.core.filtering.BaseEntryFilteringCursor;
import org.apache.directory.server.core.filtering.EntryFilteringCursor;
import org.apache.directory.server.core.interceptor.context.AddOperationContext;
import org.apache.directory.server.core.interceptor.context.BindOperationContext;
import org.apache.directory.server.core.interceptor.context.DeleteOperationContext;
import org.apache.directory.server.core.interceptor.context.EntryOperationContext;
import org.apache.directory.server.core.interceptor.context.ListOperationContext;
import org.apache.directory.server.core.interceptor.context.LookupOperationContext;
import org.apache.directory.server.core.interceptor.context.ModifyOperationContext;
import org.apache.directory.server.core.interceptor.context.MoveAndRenameOperationContext;
import org.apache.directory.server.core.interceptor.context.MoveOperationContext;
import org.apache.directory.server.core.interceptor.context.RenameOperationContext;
import org.apache.directory.server.core.interceptor.context.SearchOperationContext;
import org.apache.directory.server.core.interceptor.context.UnbindOperationContext;
import org.apache.directory.server.core.partition.Partition;
import org.apache.directory.shared.ldap.model.cursor.Cursor;
import org.apache.directory.shared.ldap.model.cursor.ListCursor;
import org.apache.directory.shared.ldap.model.entry.Entry;
import org.apache.directory.shared.ldap.model.exception.LdapException;
import org.apache.directory.shared.ldap.model.exception.LdapInvalidDnException;
import org.apache.directory.shared.ldap.model.filter.ExprNode;
import org.apache.directory.shared.ldap.model.message.SearchScope;
import org.apache.directory.shared.ldap.model.name.Dn;
import org.apache.directory.shared.ldap.model.schema.SchemaManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.structr.api.config.Settings;
import org.structr.common.SecurityContext;
import org.structr.ldap.api.LDAPNode;
import org.structr.ldap.entity.LDAPNodeImpl;
/**
*
*/
class StructrPartition implements Partition {
private static final Logger logger = LoggerFactory.getLogger(StructrPartition.class.getName());
private Class<? extends LDAPNode> rootType = null;
private SchemaManager schemaManager = null;
private boolean initialized = false;
private String id = null;
private Dn suffixDn = null;
public StructrPartition(final SchemaManager schemaManager, final String partitionId, final Dn suffixDn) {
this.id = partitionId;
this.suffixDn = suffixDn;
this.schemaManager = schemaManager;
}
@Override
public String getId() {
return id;
}
@Override
public void setId(String id) {
this.id = id;
}
@Override
public SchemaManager getSchemaManager() {
return schemaManager;
}
@Override
public void setSchemaManager(SchemaManager schemaManager) {
this.schemaManager = schemaManager;
}
@Override
public void initialize() throws LdapException {
this.initialized = true;
}
@Override
public Dn getSuffixDn() {
return suffixDn;
}
@Override
public void setSuffixDn(Dn suffixDn) throws LdapInvalidDnException {
this.suffixDn = suffixDn;
}
@Override
public void destroy() throws Exception {
}
@Override
public boolean isInitialized() {
return initialized;
}
@Override
public void sync() throws Exception {
}
@Override
public void delete(DeleteOperationContext deleteContext) throws LdapException {
final LdapPrincipal principal = deleteContext.getEffectivePrincipal();
final Dn dn = deleteContext.getDn();
getWrapper(principal).delete(dn);
}
@Override
public void add(AddOperationContext addContext) throws LdapException {
final LdapPrincipal principal = addContext.getEffectivePrincipal();
final Entry entry = addContext.getEntry();
getWrapper(principal).add(entry);
}
@Override
public void modify(ModifyOperationContext modifyContext) throws LdapException {
}
@Override
public EntryFilteringCursor list(ListOperationContext listContext) throws LdapException {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public EntryFilteringCursor search(SearchOperationContext searchContext) throws LdapException {
logger.info("{}", searchContext);
final LdapPrincipal principal = searchContext.getEffectivePrincipal();
final Dn dn = searchContext.getDn();
final ExprNode filter = searchContext.getFilter();
final SearchScope scope = searchContext.getScope();
final List<Entry> list = getWrapper(principal).filter(dn, filter, scope);
final Cursor<Entry> cursor = new ListCursor<>(list);
return new BaseEntryFilteringCursor(cursor, searchContext);
}
@Override
public Entry lookup(LookupOperationContext lookupContext) throws LdapException {
final Dn dn = lookupContext.getDn();
if (lookupContext.getSession() != null) {
return getWrapper(lookupContext.getEffectivePrincipal()).get(dn);
} else {
return getWrapper(null).get(dn);
}
}
@Override
public boolean hasEntry(EntryOperationContext hasEntryContext) throws LdapException {
final LdapPrincipal principal = hasEntryContext.getEffectivePrincipal();
final Dn dn = hasEntryContext.getDn();
return getWrapper(principal).get(dn) != null;
}
@Override
public void rename(RenameOperationContext renameContext) throws LdapException {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void move(MoveOperationContext moveContext) throws LdapException {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void moveAndRename(MoveAndRenameOperationContext moveAndRenameContext) throws LdapException {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void bind(BindOperationContext bindContext) throws LdapException {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void unbind(UnbindOperationContext unbindContext) throws LdapException {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void dumpIndex(OutputStream stream, String name) throws IOException {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
// ----- private methods -----
private StructrLDAPWrapper getWrapper(final LdapPrincipal principal) {
final SecurityContext securityContext = SecurityContext.getSuperUserInstance();
return new StructrLDAPWrapper(securityContext, schemaManager, id, getPartitionRootType());
}
private Class<? extends LDAPNode> getPartitionRootType() {
if (rootType == null) {
// try to identify root type from structr.conf
final StringBuilder keyBuilder = new StringBuilder(LDAPServerService.LDAP_PARTITION_ROOT_TYPE_PREFIX);
keyBuilder.append(this.id);
keyBuilder.append(LDAPServerService.LDAP_PARTITION_ROOT_TYPE_SUFFIX);
final String rootTypeName = Settings.getStringSetting(keyBuilder.toString()).getValue();
if (rootTypeName == null) {
logger.info("No LDAP root node type specified for partition {}, using default (LDAPNodeImpl). This default can be changed by setting a value for {} in structr.conf",
new Object[] {
id,
keyBuilder.toString()
}
);
rootType = LDAPNodeImpl.class;
} else {
try {
this.rootType = (Class<? extends LDAPNode>)Class.forName(rootTypeName);
} catch (ClassNotFoundException ex) {
logger.warn("Unable to instantiate LDAP root node class {}, falling back to default. {}", new Object[] { rootTypeName, ex.getMessage() });
}
if (rootType == null) {
rootType = LDAPNodeImpl.class;
}
}
}
return rootType;
}
}