--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * 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.argeo.node;
+
+/** Framework agnostic interface for log notifications */
+public interface ArgeoLogListener {
+ /**
+ * Appends a log
+ *
+ * @param username
+ * authentified user, null for anonymous
+ * @param level
+ * INFO, DEBUG, WARN, etc. (logging framework specific)
+ * @param category
+ * hierarchy (logging framework specific)
+ * @param thread
+ * name of the thread which logged this message
+ * @param msg
+ * any object as long as its toString() method returns the
+ * message
+ * @param the
+ * exception in log4j ThrowableStrRep format
+ */
+ public void appendLog(String username, Long timestamp, String level,
+ String category, String thread, Object msg, String[] exception);
+}
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * 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.argeo.node;
+
+/**
+ * Logging framework agnostic identifying a logging service, to which one can
+ * register
+ */
+public interface ArgeoLogger {
+ /**
+ * Register for events by threads with the same authentication (or all
+ * threads if admin)
+ */
+ public void register(ArgeoLogListener listener,
+ Integer numberOfPreviousEvents);
+
+ /**
+ * For admin use only: register for all users
+ *
+ * @param listener
+ * the log listener
+ * @param numberOfPreviousEvents
+ * the number of previous events to notify
+ * @param everything
+ * if true even anonymous is logged
+ */
+ public void registerForAll(ArgeoLogListener listener,
+ Integer numberOfPreviousEvents, boolean everything);
+
+ public void unregister(ArgeoLogListener listener);
+
+ public void unregisterForAll(ArgeoLogListener listener);
+}
/** Repository type */
type("localfs"),
/** Default workspace */
+ @Deprecated
defaultWorkspace("main"),
/** Database URL */
dburl(null),
/** The identifier (can be an URL locating the repo) */
labeledUri(null),
-
- httpPort(8080),
//
// JACKRABBIT SPECIFIC
//
/** Maximum database pool size */
maxPoolSize(10),
/** Maximum cache size in MB */
+ @Deprecated
maxCacheMB(null),
/** Bundle cache size in MB */
bundleCacheMB(8),
import javax.security.auth.callback.UnsupportedCallbackException;
import org.argeo.ArgeoException;
-import org.argeo.util.LocaleChoice;
/** Callback handler to be used with a command line UI. */
public class ConsoleCallbackHandler implements CallbackHandler {
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * 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.argeo.cms.internal.auth;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+
+import javax.security.auth.callback.LanguageCallback;
+
+import org.argeo.ArgeoException;
+
+/** Choose in a list of locales. TODO: replace with {@link LanguageCallback} */
+public class LocaleChoice {
+ private final List<Locale> locales;
+
+ private Integer selectedIndex = null;
+ private final Integer defaultIndex;
+
+ public LocaleChoice(List<Locale> locales, Locale defaultLocale) {
+ Integer defaultIndex = null;
+ this.locales = Collections.unmodifiableList(locales);
+ for (int i = 0; i < locales.size(); i++)
+ if (locales.get(i).equals(defaultLocale))
+ defaultIndex = i;
+
+ // based on language only
+ if (defaultIndex == null)
+ for (int i = 0; i < locales.size(); i++)
+ if (locales.get(i).getLanguage().equals(defaultLocale.getLanguage()))
+ defaultIndex = i;
+
+ if (defaultIndex == null)
+ throw new ArgeoException("Default locale " + defaultLocale + " is not in available locales " + locales);
+ this.defaultIndex = defaultIndex;
+
+ this.selectedIndex = defaultIndex;
+ }
+
+ /**
+ * Convenience constructor based on a comma separated list of iso codes (en,
+ * en_US, fr_CA, etc.). Default selection is default locale.
+ */
+ public LocaleChoice(String locales, Locale defaultLocale) {
+ this(asLocaleList(locales), defaultLocale);
+ }
+
+ public String[] getSupportedLocalesLabels() {
+ String[] labels = new String[locales.size()];
+ for (int i = 0; i < locales.size(); i++) {
+ Locale locale = locales.get(i);
+ if (locale.getCountry().equals(""))
+ labels[i] = locale.getDisplayLanguage(locale) + " [" + locale.getLanguage() + "]";
+ else
+ labels[i] = locale.getDisplayLanguage(locale) + " (" + locale.getDisplayCountry(locale) + ") ["
+ + locale.getLanguage() + "_" + locale.getCountry() + "]";
+
+ }
+ return labels;
+ }
+
+ public Locale getSelectedLocale() {
+ if (selectedIndex == null)
+ return null;
+ return locales.get(selectedIndex);
+ }
+
+ public void setSelectedIndex(Integer selectedIndex) {
+ this.selectedIndex = selectedIndex;
+ }
+
+ public Integer getSelectedIndex() {
+ return selectedIndex;
+ }
+
+ public Integer getDefaultIndex() {
+ return defaultIndex;
+ }
+
+ public List<Locale> getLocales() {
+ return locales;
+ }
+
+ public Locale getDefaultLocale() {
+ return locales.get(getDefaultIndex());
+ }
+
+ /** Returns null if argument is null. */
+ public static List<Locale> asLocaleList(Object locales) {
+ if (locales == null)
+ return null;
+ ArrayList<Locale> availableLocales = new ArrayList<Locale>();
+ String[] codes = locales.toString().split(",");
+ for (int i = 0; i < codes.length; i++) {
+ String code = codes[i];
+ // variant not supported
+ int indexUnd = code.indexOf("_");
+ Locale locale;
+ if (indexUnd > 0) {
+ String language = code.substring(0, indexUnd);
+ String country = code.substring(indexUnd + 1);
+ locale = new Locale(language, country);
+ } else {
+ locale = new Locale(code);
+ }
+ availableLocales.add(locale);
+ }
+ return availableLocales;
+ }
+
+ public static void main(String[] args) {
+ for (String isoL : Locale.getISOLanguages()) {
+ Locale locale = new Locale(isoL);
+ System.out.println(isoL + "\t" + locale.getDisplayLanguage() + "\t" + locale.getDisplayLanguage(locale));
+ }
+ }
+
+}
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.argeo.ArgeoLogger;
import org.argeo.cms.CmsException;
+import org.argeo.node.ArgeoLogger;
import org.argeo.node.NodeConstants;
import org.argeo.node.NodeState;
import org.argeo.node.RepoConf;
log.debug("Clean node state");
Dictionary<String, Object> envProps = getStatePropertiesFromEnvironment();
// Use the UUID of the first framework run as state UUID
- cn = KernelUtils.getFrameworkProp(Constants.FRAMEWORK_UUID);
+ cn = bc.getProperty(Constants.FRAMEWORK_UUID);
envProps.put(NodeConstants.CN, cn);
nodeConf.update(envProps);
} else {
import static bitronix.tm.TransactionManagerServices.getTransactionManager;
import static bitronix.tm.TransactionManagerServices.getTransactionSynchronizationRegistry;
import static java.util.Locale.ENGLISH;
+import static org.argeo.cms.internal.auth.LocaleChoice.asLocaleList;
import static org.argeo.cms.internal.kernel.KernelUtils.getFrameworkProp;
-import static org.argeo.util.LocaleChoice.asLocaleList;
-import static org.osgi.framework.Constants.FRAMEWORK_UUID;
import java.io.File;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.util.ArrayList;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
+import java.util.UUID;
import javax.jcr.RepositoryFactory;
import javax.transaction.TransactionManager;
private Locale defaultLocale;
private List<Locale> locales = null;
- // Standalone services
- private BitronixTransactionManager transactionManager;
- private BitronixTransactionSynchronizationRegistry transactionSynchronizationRegistry;
- private NodeRepositoryFactory repositoryFactory;
-
- // Security
- private NodeUserAdmin userAdmin;
- private RepositoryServiceFactory repositoryServiceFactory;
- private RepositoryService repositoryService;
+ // private BitronixTransactionManager transactionManager;
+ // private BitronixTransactionSynchronizationRegistry
+ // transactionSynchronizationRegistry;
+ // private NodeRepositoryFactory repositoryFactory;
+ // private NodeUserAdmin userAdmin;
+ // private RepositoryServiceFactory repositoryServiceFactory;
+ // private RepositoryService repositoryService;
// Deployment
private final CmsDeployment nodeDeployment = new CmsDeployment();
private boolean cleanState = false;
private URI nodeRepoUri = null;
- ThreadGroup threadGroup = new ThreadGroup("CMS State");
+ private ThreadGroup threadGroup = new ThreadGroup("CMS");
private KernelThread kernelThread;
+ private List<Runnable> shutdownHooks = new ArrayList<>();
private String hostname;
nodeRepoUri = KernelUtils.getOsgiInstanceUri("repos/node");
- // pre-requisite
initI18n(properties);
- initTrackers();
- // standalone services
- initTransactionManager();
- initRepositoryFactory();
- // UI
- initUi();
- // Deployment
+ initServices();
initDeployConfigs(properties);
- initUserAdmin();
- initRepositories(properties);
initWebServer();
initNodeDeployment();
// kernel thread
- kernelThread = new KernelThread(this);
+ kernelThread = new KernelThread(threadGroup, "Kernel Thread");
kernelThread.setContextClassLoader(getClass().getClassLoader());
kernelThread.start();
} catch (Exception e) {
}
}
- private void initTrackers() {
- new ServiceTracker<HttpService, HttpService>(bc, HttpService.class, new PrepareHttpStc()).open();
- new ServiceTracker<>(bc, RepositoryContext.class, new RepositoryContextStc()).open();
- }
-
private void initI18n(Dictionary<String, ?> stateProps) {
Object defaultLocaleValue = stateProps.get(NodeConstants.I18N_DEFAULT_LOCALE);
defaultLocale = defaultLocaleValue != null ? new Locale(defaultLocaleValue.toString())
locales = asLocaleList(stateProps.get(NodeConstants.I18N_LOCALES));
}
+ private void initServices() {
+ // trackers
+ new ServiceTracker<HttpService, HttpService>(bc, HttpService.class, new PrepareHttpStc()).open();
+ new ServiceTracker<>(bc, RepositoryContext.class, new RepositoryContextStc()).open();
+
+ initTransactionManager();
+
+ // JCR
+ RepositoryServiceFactory repositoryServiceFactory = new RepositoryServiceFactory();
+ shutdownHooks.add(() -> repositoryServiceFactory.shutdown());
+ bc.registerService(ManagedServiceFactory.class, repositoryServiceFactory,
+ LangUtils.init(Constants.SERVICE_PID, NodeConstants.JACKRABBIT_FACTORY_PID));
+
+ NodeRepositoryFactory repositoryFactory = new NodeRepositoryFactory();
+ bc.registerService(RepositoryFactory.class, repositoryFactory, null);
+
+ RepositoryService repositoryService = new RepositoryService();
+ shutdownHooks.add(() -> repositoryService.shutdown());
+ bc.registerService(LangUtils.names(ManagedService.class, MetaTypeProvider.class), repositoryService,
+ LangUtils.init(Constants.SERVICE_PID, NodeConstants.NODE_REPO_PID));
+
+ // Security
+ NodeUserAdmin userAdmin = new NodeUserAdmin();
+ shutdownHooks.add(() -> userAdmin.destroy());
+ Dictionary<String, Object> props = userAdmin.currentState();
+ props.put(Constants.SERVICE_PID, NodeConstants.NODE_USER_ADMIN_PID);
+ bc.registerService(UserAdmin.class, userAdmin, props);
+
+ // UI
+ bc.registerService(ApplicationConfiguration.class, new MaintenanceUi(),
+ LangUtils.init(PROPERTY_CONTEXT_NAME, "system"));
+ bc.registerService(ApplicationConfiguration.class, new UserUi(), LangUtils.init(PROPERTY_CONTEXT_NAME, "user"));
+ }
+ // private void initUserAdmin() {
+ // userAdmin = new NodeUserAdmin();
+ // // register
+ // Dictionary<String, Object> props = userAdmin.currentState();
+ // props.put(Constants.SERVICE_PID, NodeConstants.NODE_USER_ADMIN_PID);
+ // // TODO use ManagedService
+ // bc.registerService(UserAdmin.class, userAdmin, props);
+ // }
+
private void initTransactionManager() {
+ // TODO manage it in a managed service, as startup could be long
+ ServiceReference<TransactionManager> existingTm = bc.getServiceReference(TransactionManager.class);
+ if (existingTm != null) {
+ if (log.isDebugEnabled())
+ log.debug("Using provided transaction manager " + existingTm);
+ }
bitronix.tm.Configuration tmConf = TransactionManagerServices.getConfiguration();
- tmConf.setServerId(getFrameworkProp(FRAMEWORK_UUID));
+ tmConf.setServerId(UUID.randomUUID().toString());
Bundle bitronixBundle = FrameworkUtil.getBundle(bitronix.tm.Configuration.class);
File tmBaseDir = bitronixBundle.getDataFile(KernelConstants.DIR_TRANSACTIONS);
File tmDir2 = new File(tmBaseDir, "btm2");
tmDir2.mkdirs();
tmConf.setLogPart2Filename(new File(tmDir2, tmDir2.getName() + ".tlog").getAbsolutePath());
- transactionManager = getTransactionManager();
- transactionSynchronizationRegistry = getTransactionSynchronizationRegistry();
+
+ BitronixTransactionManager transactionManager = getTransactionManager();
+ shutdownHooks.add(() -> transactionManager.shutdown());
+ BitronixTransactionSynchronizationRegistry transactionSynchronizationRegistry = getTransactionSynchronizationRegistry();
// register
bc.registerService(TransactionManager.class, transactionManager, null);
bc.registerService(UserTransaction.class, transactionManager, null);
bc.registerService(TransactionSynchronizationRegistry.class, transactionSynchronizationRegistry, null);
+ if (log.isDebugEnabled())
+ log.debug("Initialised default Bitronix transaction manager");
}
- private void initRepositoryFactory() {
- // TODO rationalise RepositoryFactory
- repositoryFactory = new NodeRepositoryFactory();
- // register
- bc.registerService(RepositoryFactory.class, repositoryFactory, null);
- }
+ // private void initRepositoryFactory() {
+ // // TODO rationalise RepositoryFactory
+ // repositoryFactory = new NodeRepositoryFactory();
+ // // register
+ // bc.registerService(RepositoryFactory.class, repositoryFactory, null);
+ // }
- private void initUi() {
- bc.registerService(ApplicationConfiguration.class, new MaintenanceUi(),
- LangUtils.init(PROPERTY_CONTEXT_NAME, "system"));
- bc.registerService(ApplicationConfiguration.class, new UserUi(), LangUtils.init(PROPERTY_CONTEXT_NAME, "user"));
- }
+ // private void initUi() {
+ // bc.registerService(ApplicationConfiguration.class, new MaintenanceUi(),
+ // LangUtils.init(PROPERTY_CONTEXT_NAME, "system"));
+ // bc.registerService(ApplicationConfiguration.class, new UserUi(),
+ // LangUtils.init(PROPERTY_CONTEXT_NAME, "user"));
+ // }
private void initDeployConfigs(Dictionary<String, ?> stateProps) throws IOException {
Path deployPath = KernelUtils.getOsgiInstancePath(KernelConstants.DIR_NODE + '/' + KernelConstants.DIR_DEPLOY);
}
}
- private void initUserAdmin() {
- userAdmin = new NodeUserAdmin();
- // register
- Dictionary<String, Object> props = userAdmin.currentState();
- props.put(Constants.SERVICE_PID, NodeConstants.NODE_USER_ADMIN_PID);
- // TODO use ManagedService
- bc.registerService(UserAdmin.class, userAdmin, props);
- }
-
- private void initRepositories(Dictionary<String, ?> stateProps) throws IOException {
- // register
- repositoryServiceFactory = new RepositoryServiceFactory();
- bc.registerService(ManagedServiceFactory.class, repositoryServiceFactory,
- LangUtils.init(Constants.SERVICE_PID, NodeConstants.JACKRABBIT_FACTORY_PID));
-
- repositoryService = new RepositoryService();
- Dictionary<String, Object> regProps = LangUtils.init(Constants.SERVICE_PID, NodeConstants.NODE_REPO_PID);
- bc.registerService(LangUtils.names(ManagedService.class, MetaTypeProvider.class), repositoryService, regProps);
- }
+ // private void initRepositories(Dictionary<String, ?> stateProps) throws
+ // IOException {
+ // // register
+ // repositoryServiceFactory = new RepositoryServiceFactory();
+ // bc.registerService(ManagedServiceFactory.class, repositoryServiceFactory,
+ // LangUtils.init(Constants.SERVICE_PID,
+ // NodeConstants.JACKRABBIT_FACTORY_PID));
+ //
+ // repositoryService = new RepositoryService();
+ // Dictionary<String, Object> regProps =
+ // LangUtils.init(Constants.SERVICE_PID, NodeConstants.NODE_REPO_PID);
+ // bc.registerService(LangUtils.names(ManagedService.class,
+ // MetaTypeProvider.class), repositoryService, regProps);
+ // }
private void initWebServer() {
String httpPort = getFrameworkProp("org.osgi.service.http.port");
}
void shutdown() {
+ // if (transactionManager != null)
+ // transactionManager.shutdown();
+ // if (userAdmin != null)
+ // userAdmin.destroy();
+ // if (repositoryServiceFactory != null)
+ // repositoryServiceFactory.shutdown();
+
+ applyShutdownHooks();
+
if (kernelThread != null)
kernelThread.destroyAndJoin();
- if (transactionManager != null)
- transactionManager.shutdown();
- if (userAdmin != null)
- userAdmin.destroy();
- if (repositoryServiceFactory != null)
- repositoryServiceFactory.shutdown();
+ if (log.isDebugEnabled())
+ log.debug("## CMS STOPPED");
+ }
+ /** Apply shutdown hoos in reverse order. */
+ private void applyShutdownHooks() {
+ for (int i = shutdownHooks.size() - 1; i >= 0; i--) {
+ try {
+ // new Thread(shutdownHooks.get(i), "CMS Shutdown Hook #" +
+ // i).start();
+ shutdownHooks.get(i).run();
+ } catch (Exception e) {
+ log.error("Could not run shutdown hook #" + i);
+ }
+ }
// Clean hanging Gogo shell thread
new GogoShellKiller().start();
-
- if (log.isDebugEnabled())
- log.debug("## CMS STOPPED");
}
private Dictionary<String, Object> getNodeConfig(Dictionary<String, ?> properties) {
private class GogoShellKiller extends Thread {
public GogoShellKiller() {
- super("Gogo shell killer");
+ super("Gogo Shell Killer");
setDaemon(true);
}
+++ /dev/null
-package org.argeo.cms.internal.kernel;
-
-import java.util.List;
-import java.util.Locale;
-
-public interface KernelHeader {
- public Locale getDefaultLocale();
-
- public List<Locale> getLocales();
-}
@SuppressWarnings("unused")
private long cycle = 0l;
- public KernelThread(CmsState cmState) {
- super(cmState.threadGroup, cmState.getClass().getSimpleName());
+ public KernelThread(ThreadGroup threadGroup, String name) {
+ super(threadGroup, name);
}
private void doSmallestPeriod() {
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.spi.LoggingEvent;
import org.argeo.ArgeoException;
-import org.argeo.ArgeoLogListener;
-import org.argeo.ArgeoLogger;
import org.argeo.cms.auth.CurrentUser;
+import org.argeo.node.ArgeoLogListener;
+import org.argeo.node.ArgeoLogger;
import org.osgi.service.log.LogEntry;
import org.osgi.service.log.LogListener;
import org.osgi.service.log.LogReaderService;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
import org.osgi.service.useradmin.Authorization;
import org.osgi.service.useradmin.Role;
import org.osgi.service.useradmin.User;
* Aggregates multiple {@link UserDirectory} and integrates them with this node
* system roles.
*/
-public class NodeUserAdmin implements UserAdmin, KernelConstants {
+class NodeUserAdmin implements UserAdmin, ManagedService, KernelConstants {
private final static Log log = LogFactory.getLog(NodeUserAdmin.class);
final static LdapName ROLES_BASE;
static {
new ServiceTracker<>(bc, TransactionManager.class, new TransactionManagerStc()).open();
}
+ @Override
+ public void updated(Dictionary<String, ?> properties) throws ConfigurationException {
+ }
+
private class TransactionManagerStc implements ServiceTrackerCustomizer<TransactionManager, TransactionManager> {
@Override
private ServiceRegistration<RepositoryContext> repositoryContextReg;
@Override
- public synchronized void updated(Dictionary<String, ?> properties) throws ConfigurationException {
+ public void updated(Dictionary<String, ?> properties) throws ConfigurationException {
if (properties == null)
return;
}
- public synchronized void shutdown() {
+ public void shutdown() {
if (repositoryContextReg == null)
return;
RepositoryContext repositoryContext = bc.getService(repositoryContextReg.getReference());
--- /dev/null
+package org.argeo.cms.internal.kernel;
+
+import java.io.FilePermission;
+import java.lang.reflect.ReflectPermission;
+import java.net.SocketPermission;
+import java.security.AllPermission;
+import java.util.PropertyPermission;
+
+import javax.management.MBeanPermission;
+import javax.management.MBeanServerPermission;
+import javax.management.MBeanTrustPermission;
+import javax.security.auth.AuthPermission;
+
+import org.osgi.framework.AdminPermission;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServicePermission;
+import org.osgi.service.cm.ConfigurationPermission;
+import org.osgi.service.condpermadmin.BundleLocationCondition;
+import org.osgi.service.condpermadmin.ConditionInfo;
+import org.osgi.service.condpermadmin.ConditionalPermissionAdmin;
+import org.osgi.service.condpermadmin.ConditionalPermissionInfo;
+import org.osgi.service.condpermadmin.ConditionalPermissionUpdate;
+import org.osgi.service.permissionadmin.PermissionInfo;
+
+import bitronix.tm.BitronixTransactionManager;
+
+public interface SecurityProfile {
+ BundleContext bc = FrameworkUtil.getBundle(SecurityProfile.class).getBundleContext();
+
+ default void applySystemPermissions(ConditionalPermissionAdmin permissionAdmin) {
+ ConditionalPermissionUpdate update = permissionAdmin.newConditionalPermissionUpdate();
+ // Self
+ update.getConditionalPermissionInfos()
+ .add(permissionAdmin.newConditionalPermissionInfo(null,
+ new ConditionInfo[] { new ConditionInfo(BundleLocationCondition.class.getName(),
+ new String[] { locate(SecurityProfile.class) }) },
+ new PermissionInfo[] { new PermissionInfo(AllPermission.class.getName(), null, null) },
+ ConditionalPermissionInfo.ALLOW));
+ update.getConditionalPermissionInfos()
+ .add(permissionAdmin.newConditionalPermissionInfo(null,
+ new ConditionInfo[] { new ConditionInfo(BundleLocationCondition.class.getName(),
+ new String[] { bc.getBundle(0).getLocation() }) },
+ new PermissionInfo[] { new PermissionInfo(AllPermission.class.getName(), null, null) },
+ ConditionalPermissionInfo.ALLOW));
+ // All
+ // FIXME understand why Jetty and Jackrabbit require that
+ update.getConditionalPermissionInfos()
+ .add(permissionAdmin.newConditionalPermissionInfo(null, null, new PermissionInfo[] {
+ new PermissionInfo(SocketPermission.class.getName(), "localhost:7070", "listen,resolve"),
+ new PermissionInfo(FilePermission.class.getName(), "<<ALL FILES>>", "read,write,delete"),
+ new PermissionInfo(PropertyPermission.class.getName(), "DEBUG", "read"),
+ new PermissionInfo(PropertyPermission.class.getName(), "STOP.*", "read"),
+ new PermissionInfo(PropertyPermission.class.getName(), "org.apache.jackrabbit.*", "read"),
+ new PermissionInfo(RuntimePermission.class.getName(), "*", "*"), },
+ ConditionalPermissionInfo.ALLOW));
+
+ // Eclipse
+ // update.getConditionalPermissionInfos()
+ // .add(permissionAdmin.newConditionalPermissionInfo(null,
+ // new ConditionInfo[] { new
+ // ConditionInfo(BundleLocationCondition.class.getName(),
+ // new String[] { "*/org.eclipse.*" }) },
+ // new PermissionInfo[] { new
+ // PermissionInfo(RuntimePermission.class.getName(), "*", "*"),
+ // new PermissionInfo(AdminPermission.class.getName(), "*", "*"),
+ // new PermissionInfo(ServicePermission.class.getName(), "*", "get"),
+ // new PermissionInfo(ServicePermission.class.getName(), "*",
+ // "register"),
+ // new PermissionInfo(TopicPermission.class.getName(), "*", "publish"),
+ // new PermissionInfo(TopicPermission.class.getName(), "*",
+ // "subscribe"),
+ // new PermissionInfo(PropertyPermission.class.getName(), "osgi.*",
+ // "read"),
+ // new PermissionInfo(PropertyPermission.class.getName(), "eclipse.*",
+ // "read"),
+ // new PermissionInfo(PropertyPermission.class.getName(),
+ // "org.eclipse.*", "read"),
+ // new PermissionInfo(PropertyPermission.class.getName(), "equinox.*",
+ // "read"),
+ // new PermissionInfo(PropertyPermission.class.getName(), "xml.*",
+ // "read"),
+ // new PermissionInfo("org.eclipse.equinox.log.LogPermission", "*",
+ // "log"), },
+ // ConditionalPermissionInfo.ALLOW));
+ update.getConditionalPermissionInfos()
+ .add(permissionAdmin.newConditionalPermissionInfo(null,
+ new ConditionInfo[] { new ConditionInfo(BundleLocationCondition.class.getName(),
+ new String[] { "*/org.eclipse.*" }) },
+ new PermissionInfo[] { new PermissionInfo(AllPermission.class.getName(), null, null), },
+ ConditionalPermissionInfo.ALLOW));
+ update.getConditionalPermissionInfos()
+ .add(permissionAdmin.newConditionalPermissionInfo(null,
+ new ConditionInfo[] { new ConditionInfo(BundleLocationCondition.class.getName(),
+ new String[] { "*/org.apache.felix.*" }) },
+ new PermissionInfo[] { new PermissionInfo(AllPermission.class.getName(), null, null), },
+ ConditionalPermissionInfo.ALLOW));
+
+ // Configuration admin
+// update.getConditionalPermissionInfos().add(permissionAdmin.newConditionalPermissionInfo(null,
+// new ConditionInfo[] { new ConditionInfo(BundleLocationCondition.class.getName(),
+// new String[] { locate(configurationAdmin.getService().getClass()) }) },
+// new PermissionInfo[] { new PermissionInfo(ConfigurationPermission.class.getName(), "*", "configure"),
+// new PermissionInfo(AdminPermission.class.getName(), "*", "*"),
+// new PermissionInfo(PropertyPermission.class.getName(), "osgi.*", "read"), },
+// ConditionalPermissionInfo.ALLOW));
+
+ // Bitronix
+ update.getConditionalPermissionInfos().add(permissionAdmin.newConditionalPermissionInfo(null,
+ new ConditionInfo[] { new ConditionInfo(BundleLocationCondition.class.getName(),
+ new String[] { locate(BitronixTransactionManager.class) }) },
+ new PermissionInfo[] { new PermissionInfo(PropertyPermission.class.getName(), "bitronix.tm.*", "read"),
+ new PermissionInfo(RuntimePermission.class.getName(), "getClassLoader", null),
+ new PermissionInfo(MBeanServerPermission.class.getName(), "createMBeanServer", null),
+ new PermissionInfo(MBeanPermission.class.getName(), "bitronix.tm.*", "registerMBean"),
+ new PermissionInfo(MBeanTrustPermission.class.getName(), "register", null) },
+ ConditionalPermissionInfo.ALLOW));
+
+ // DS
+ Bundle dsBundle = findBundle("org.eclipse.equinox.ds");
+ update.getConditionalPermissionInfos().add(permissionAdmin.newConditionalPermissionInfo(null,
+ new ConditionInfo[] { new ConditionInfo(BundleLocationCondition.class.getName(),
+ new String[] { dsBundle.getLocation() }) },
+ new PermissionInfo[] { new PermissionInfo(ConfigurationPermission.class.getName(), "*", "configure"),
+ new PermissionInfo(AdminPermission.class.getName(), "*", "*"),
+ new PermissionInfo(ServicePermission.class.getName(), "*", "get"),
+ new PermissionInfo(ServicePermission.class.getName(), "*", "register"),
+ new PermissionInfo(PropertyPermission.class.getName(), "osgi.*", "read"),
+ new PermissionInfo(PropertyPermission.class.getName(), "xml.*", "read"),
+ new PermissionInfo(PropertyPermission.class.getName(), "equinox.*", "read"),
+ new PermissionInfo(RuntimePermission.class.getName(), "accessDeclaredMembers", null),
+ new PermissionInfo(RuntimePermission.class.getName(), "getClassLoader", null),
+ new PermissionInfo(ReflectPermission.class.getName(), "suppressAccessChecks", null), },
+ ConditionalPermissionInfo.ALLOW));
+
+ // Jetty
+ Bundle jettyUtilBundle = findBundle("org.eclipse.equinox.http.jetty");
+ update.getConditionalPermissionInfos().add(permissionAdmin.newConditionalPermissionInfo(null,
+ new ConditionInfo[] { new ConditionInfo(BundleLocationCondition.class.getName(),
+ new String[] { "*/org.eclipse.jetty.*" }) },
+ new PermissionInfo[] {
+ new PermissionInfo(FilePermission.class.getName(), "<<ALL FILES>>", "read,write,delete"), },
+ ConditionalPermissionInfo.ALLOW));
+
+ // Blueprint
+ Bundle blueprintBundle = findBundle("org.eclipse.gemini.blueprint.core");
+ update.getConditionalPermissionInfos()
+ .add(permissionAdmin.newConditionalPermissionInfo(null,
+ new ConditionInfo[] { new ConditionInfo(BundleLocationCondition.class.getName(),
+ new String[] { blueprintBundle.getLocation() }) },
+ new PermissionInfo[] { new PermissionInfo(RuntimePermission.class.getName(), "*", null),
+ new PermissionInfo(AdminPermission.class.getName(), "*", "*"), },
+ ConditionalPermissionInfo.ALLOW));
+ Bundle blueprintExtenderBundle = findBundle("org.eclipse.gemini.blueprint.extender");
+ update.getConditionalPermissionInfos()
+ .add(permissionAdmin
+ .newConditionalPermissionInfo(null,
+ new ConditionInfo[] { new ConditionInfo(BundleLocationCondition.class.getName(),
+ new String[] { blueprintExtenderBundle.getLocation() }) },
+ new PermissionInfo[] { new PermissionInfo(RuntimePermission.class.getName(), "*", null),
+ new PermissionInfo(PropertyPermission.class.getName(), "org.eclipse.gemini.*",
+ "read"),
+ new PermissionInfo(AdminPermission.class.getName(), "*", "*"),
+ new PermissionInfo(ServicePermission.class.getName(), "*", "register"), },
+ ConditionalPermissionInfo.ALLOW));
+ Bundle springCoreBundle = findBundle("org.springframework.core");
+ update.getConditionalPermissionInfos()
+ .add(permissionAdmin.newConditionalPermissionInfo(null,
+ new ConditionInfo[] { new ConditionInfo(BundleLocationCondition.class.getName(),
+ new String[] { springCoreBundle.getLocation() }) },
+ new PermissionInfo[] { new PermissionInfo(RuntimePermission.class.getName(), "*", null),
+ new PermissionInfo(AdminPermission.class.getName(), "*", "*"), },
+ ConditionalPermissionInfo.ALLOW));
+ Bundle blueprintIoBundle = findBundle("org.eclipse.gemini.blueprint.io");
+ update.getConditionalPermissionInfos()
+ .add(permissionAdmin.newConditionalPermissionInfo(null,
+ new ConditionInfo[] { new ConditionInfo(BundleLocationCondition.class.getName(),
+ new String[] { blueprintIoBundle.getLocation() }) },
+ new PermissionInfo[] { new PermissionInfo(RuntimePermission.class.getName(), "*", null),
+ new PermissionInfo(AdminPermission.class.getName(), "*", "*"), },
+ ConditionalPermissionInfo.ALLOW));
+
+ // Equinox
+ Bundle registryBundle = findBundle("org.eclipse.equinox.registry");
+ update.getConditionalPermissionInfos().add(permissionAdmin.newConditionalPermissionInfo(null,
+ new ConditionInfo[] { new ConditionInfo(BundleLocationCondition.class.getName(),
+ new String[] { registryBundle.getLocation() }) },
+ new PermissionInfo[] { new PermissionInfo(PropertyPermission.class.getName(), "eclipse.*", "read"),
+ new PermissionInfo(PropertyPermission.class.getName(), "osgi.*", "read"),
+ new PermissionInfo(FilePermission.class.getName(), "<<ALL FILES>>", "read,write,delete"), },
+ ConditionalPermissionInfo.ALLOW));
+
+ Bundle equinoxUtilBundle = findBundle("org.eclipse.equinox.util");
+ update.getConditionalPermissionInfos().add(permissionAdmin.newConditionalPermissionInfo(null,
+ new ConditionInfo[] { new ConditionInfo(BundleLocationCondition.class.getName(),
+ new String[] { equinoxUtilBundle.getLocation() }) },
+ new PermissionInfo[] { new PermissionInfo(PropertyPermission.class.getName(), "equinox.*", "read"),
+ new PermissionInfo(ServicePermission.class.getName(), "*", "get"),
+ new PermissionInfo(ServicePermission.class.getName(), "*", "register"), },
+ ConditionalPermissionInfo.ALLOW));
+ Bundle equinoxCommonBundle = findBundle("org.eclipse.equinox.common");
+ update.getConditionalPermissionInfos()
+ .add(permissionAdmin.newConditionalPermissionInfo(null,
+ new ConditionInfo[] { new ConditionInfo(BundleLocationCondition.class.getName(),
+ new String[] { equinoxCommonBundle.getLocation() }) },
+ new PermissionInfo[] { new PermissionInfo(AdminPermission.class.getName(), "*", "*"), },
+ ConditionalPermissionInfo.ALLOW));
+
+ Bundle consoleBundle = findBundle("org.eclipse.equinox.console");
+ update.getConditionalPermissionInfos()
+ .add(permissionAdmin.newConditionalPermissionInfo(null,
+ new ConditionInfo[] { new ConditionInfo(BundleLocationCondition.class.getName(),
+ new String[] { consoleBundle.getLocation() }) },
+ new PermissionInfo[] { new PermissionInfo(ServicePermission.class.getName(), "*", "register"),
+ new PermissionInfo(AdminPermission.class.getName(), "*", "listener") },
+ ConditionalPermissionInfo.ALLOW));
+ Bundle preferencesBundle = findBundle("org.eclipse.equinox.preferences");
+ update.getConditionalPermissionInfos().add(permissionAdmin.newConditionalPermissionInfo(null,
+ new ConditionInfo[] { new ConditionInfo(BundleLocationCondition.class.getName(),
+ new String[] { preferencesBundle.getLocation() }) },
+ new PermissionInfo[] {
+ new PermissionInfo(FilePermission.class.getName(), "<<ALL FILES>>", "read,write,delete"), },
+ ConditionalPermissionInfo.ALLOW));
+ Bundle appBundle = findBundle("org.eclipse.equinox.app");
+ update.getConditionalPermissionInfos().add(permissionAdmin.newConditionalPermissionInfo(null,
+ new ConditionInfo[] { new ConditionInfo(BundleLocationCondition.class.getName(),
+ new String[] { appBundle.getLocation() }) },
+ new PermissionInfo[] {
+ new PermissionInfo(FilePermission.class.getName(), "<<ALL FILES>>", "read,write,delete"), },
+ ConditionalPermissionInfo.ALLOW));
+
+ // Jackrabbit
+ Bundle jackrabbitCoreBundle = findBundle("org.apache.jackrabbit.core");
+ update.getConditionalPermissionInfos().add(permissionAdmin.newConditionalPermissionInfo(null,
+ new ConditionInfo[] { new ConditionInfo(BundleLocationCondition.class.getName(),
+ new String[] { jackrabbitCoreBundle.getLocation() }) },
+ new PermissionInfo[] {
+ new PermissionInfo(FilePermission.class.getName(), "<<ALL FILES>>", "read,write,delete"),
+ new PermissionInfo(PropertyPermission.class.getName(), "*", "read,write"),
+ new PermissionInfo(AuthPermission.class.getName(), "getLoginConfiguration", null),
+ new PermissionInfo(AuthPermission.class.getName(), "createLoginContext.Jackrabbit", null), },
+ ConditionalPermissionInfo.ALLOW));
+ Bundle jackrabbitCommonBundle = findBundle("org.apache.jackrabbit.jcr.commons");
+ update.getConditionalPermissionInfos().add(permissionAdmin.newConditionalPermissionInfo(null,
+ new ConditionInfo[] { new ConditionInfo(BundleLocationCondition.class.getName(),
+ new String[] { jackrabbitCommonBundle.getLocation() }) },
+ new PermissionInfo[] {
+ new PermissionInfo(AuthPermission.class.getName(), "createLoginContext.Jackrabbit", null), },
+ ConditionalPermissionInfo.ALLOW));
+ Bundle tikaCoreBundle = findBundle("org.apache.tika.core");
+ update.getConditionalPermissionInfos()
+ .add(permissionAdmin.newConditionalPermissionInfo(null,
+ new ConditionInfo[] { new ConditionInfo(BundleLocationCondition.class.getName(),
+ new String[] { tikaCoreBundle.getLocation() }) },
+ new PermissionInfo[] { new PermissionInfo(PropertyPermission.class.getName(), "*", "read"),
+ new PermissionInfo(AdminPermission.class.getName(), "*", "*") },
+ ConditionalPermissionInfo.ALLOW));
+ Bundle luceneBundle = findBundle("org.apache.lucene");
+ update.getConditionalPermissionInfos()
+ .add(permissionAdmin.newConditionalPermissionInfo(null,
+ new ConditionInfo[] { new ConditionInfo(BundleLocationCondition.class.getName(),
+ new String[] { luceneBundle.getLocation() }) },
+ new PermissionInfo[] {
+ new PermissionInfo(FilePermission.class.getName(), "<<ALL FILES>>",
+ "read,write,delete"),
+ new PermissionInfo(PropertyPermission.class.getName(), "*", "read"),
+ new PermissionInfo(AdminPermission.class.getName(), "*", "*") },
+ ConditionalPermissionInfo.ALLOW));
+
+ // COMMIT
+ update.commit();
+ }
+
+ /** @return bundle location */
+ default String locate(Class<?> clzz) {
+ return FrameworkUtil.getBundle(clzz).getLocation();
+ }
+
+ /** Can be null */
+ default Bundle findBundle(String symbolicName) {
+ for (Bundle b : bc.getBundles())
+ if (b.getSymbolicName().equals(symbolicName))
+ return b;
+ return null;
+ }
+
+}
import org.argeo.cms.auth.CurrentUser;
import org.argeo.cms.auth.HttpRequestCallback;
import org.argeo.cms.i18n.LocaleUtils;
+import org.argeo.cms.internal.auth.LocaleChoice;
import org.argeo.cms.util.CmsUtils;
import org.argeo.eclipse.ui.dialogs.ErrorFeedback;
-import org.argeo.util.LocaleChoice;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
import javax.security.auth.callback.TextOutputCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
-import org.argeo.util.LocaleChoice;
+import org.argeo.cms.internal.auth.LocaleChoice;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
+import org.argeo.util.naming.LdifParser;
public class LdifParserTest extends TestCase implements BasicTestConstants {
public void testBasicLdif() throws Exception {
+++ /dev/null
-package org.argeo.osgi.useradmin;
-
-import static org.argeo.osgi.useradmin.LdifName.dn;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.List;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-import javax.naming.InvalidNameException;
-import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.BasicAttribute;
-import javax.naming.directory.BasicAttributes;
-import javax.naming.ldap.LdapName;
-import javax.naming.ldap.Rdn;
-
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/** Basic LDIF parser. */
-class LdifParser {
- private final static Log log = LogFactory.getLog(LdifParser.class);
-
- protected Attributes addAttributes(SortedMap<LdapName, Attributes> res,
- int lineNumber, LdapName currentDn, Attributes currentAttributes) {
- try {
- Rdn nameRdn = currentDn.getRdn(currentDn.size() - 1);
- Attribute nameAttr = currentAttributes.get(nameRdn.getType());
- if (nameAttr == null)
- currentAttributes.put(nameRdn.getType(), nameRdn.getValue());
- else if (!nameAttr.get().equals(nameRdn.getValue()))
- throw new UserDirectoryException("Attribute "
- + nameAttr.getID() + "=" + nameAttr.get()
- + " not consistent with DN " + currentDn
- + " (shortly before line " + lineNumber
- + " in LDIF file)");
- Attributes previous = res.put(currentDn, currentAttributes);
- if (log.isTraceEnabled())
- log.trace("Added " + currentDn);
- return previous;
- } catch (NamingException e) {
- throw new UserDirectoryException("Cannot add " + currentDn, e);
- }
- }
-
- static void checkDnConsistency() {
-
- }
-
- SortedMap<LdapName, Attributes> read(InputStream in) throws IOException {
- SortedMap<LdapName, Attributes> res = new TreeMap<LdapName, Attributes>();
- try {
- List<String> lines = IOUtils.readLines(in);
- // add an empty new line since the last line is not checked
- if (!lines.get(lines.size() - 1).equals(""))
- lines.add("");
-
- LdapName currentDn = null;
- Attributes currentAttributes = null;
- StringBuilder currentEntry = new StringBuilder();
-
- readLines: for (int lineNumber = 0; lineNumber < lines.size(); lineNumber++) {
- String line = lines.get(lineNumber);
- boolean isLastLine = false;
- if (lineNumber == lines.size() - 1)
- isLastLine = true;
- if (line.startsWith(" ")) {
- currentEntry.append(line.substring(1));
- if (!isLastLine)
- continue readLines;
- }
-
- if (currentEntry.length() != 0 || isLastLine) {
- // read previous attribute
- StringBuilder attrId = new StringBuilder(8);
- boolean isBase64 = false;
- readAttrId: for (int i = 0; i < currentEntry.length(); i++) {
- char c = currentEntry.charAt(i);
- if (c == ':') {
- if (i + 1 < currentEntry.length()
- && currentEntry.charAt(i + 1) == ':')
- isBase64 = true;
- currentEntry.delete(0, i + (isBase64 ? 2 : 1));
- break readAttrId;
- } else {
- attrId.append(c);
- }
- }
-
- String attributeId = attrId.toString();
- String cleanValueStr = currentEntry.toString().trim();
- Object attributeValue = isBase64 ? Base64
- .decodeBase64(cleanValueStr) : cleanValueStr;
-
- // manage DN attributes
- if (attributeId.equals(dn.name()) || isLastLine) {
- if (currentDn != null) {
- //
- // ADD
- //
- Attributes previous = addAttributes(res,
- lineNumber, currentDn, currentAttributes);
- if (previous != null) {
- log.warn("There was already an entry with DN "
- + currentDn
- + ", which has been discarded by a subsequent one.");
- }
- }
-
- if (attributeId.equals(dn.name()))
- try {
- currentDn = new LdapName(
- attributeValue.toString());
- currentAttributes = new BasicAttributes(true);
- } catch (InvalidNameException e) {
- log.error(attributeValue
- + " not a valid DN, skipping the entry.");
- currentDn = null;
- currentAttributes = null;
- }
- }
-
- // store attribute
- if (currentAttributes != null) {
- Attribute attribute = currentAttributes
- .get(attributeId);
- if (attribute == null) {
- attribute = new BasicAttribute(attributeId);
- currentAttributes.put(attribute);
- }
- attribute.add(attributeValue);
- }
- currentEntry = new StringBuilder();
- }
- currentEntry.append(line);
- }
- } finally {
- IOUtils.closeQuietly(in);
- }
- return res;
- }
-}
\ No newline at end of file
import javax.transaction.TransactionManager;
import org.apache.commons.io.IOUtils;
+import org.argeo.util.naming.LdifParser;
+import org.argeo.util.naming.LdifWriter;
import org.osgi.framework.Filter;
import org.osgi.service.useradmin.Role;
+++ /dev/null
-package org.argeo.osgi.useradmin;
-
-import static org.argeo.osgi.useradmin.LdifName.dn;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.ldap.LdapName;
-import javax.naming.ldap.Rdn;
-
-import org.apache.commons.codec.binary.Base64;
-
-/** Basic LDIF writer */
-class LdifWriter {
- private final Writer writer;
-
- LdifWriter(OutputStream out) {
- this.writer = new OutputStreamWriter(out);
- }
-
- void writeEntry(LdapName name, Attributes attributes) throws IOException {
- try {
- // check consistency
- Rdn nameRdn = name.getRdn(name.size() - 1);
- Attribute nameAttr = attributes.get(nameRdn.getType());
- if (!nameAttr.get().equals(nameRdn.getValue()))
- throw new UserDirectoryException("Attribute "
- + nameAttr.getID() + "=" + nameAttr.get()
- + " not consistent with DN " + name);
-
- writer.append(dn.name() + ":").append(name.toString()).append('\n');
- Attribute objectClassAttr = attributes.get("objectClass");
- if (objectClassAttr != null)
- writeAttribute(objectClassAttr);
- for (NamingEnumeration<? extends Attribute> attrs = attributes
- .getAll(); attrs.hasMore();) {
- Attribute attribute = attrs.next();
- if (attribute.getID().equals(dn.name())
- || attribute.getID().equals("objectClass"))
- continue;// skip DN attribute
- writeAttribute(attribute);
- }
- writer.append('\n');
- writer.flush();
- } catch (NamingException e) {
- throw new UserDirectoryException("Cannot write LDIF", e);
- }
- }
-
- private void writeAttribute(Attribute attribute) throws NamingException,
- IOException {
- for (NamingEnumeration<?> attrValues = attribute.getAll(); attrValues
- .hasMore();) {
- Object value = attrValues.next();
- if (value instanceof byte[]) {
- String encoded = Base64.encodeBase64String((byte[]) value);
- writer.append(attribute.getID()).append("::").append(encoded)
- .append('\n');
- } else {
- writer.append(attribute.getID()).append(':')
- .append(value.toString()).append('\n');
- }
- }
- }
-}
--- /dev/null
+package org.argeo.util.naming;
+
+import java.util.Dictionary;
+import java.util.Enumeration;
+
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttribute;
+
+public class AttributesDictionary extends Dictionary<String, Object> {
+ private final Attributes attributes;
+
+ /** The provided attributes is wrapped, not copied. */
+ public AttributesDictionary(Attributes attributes) {
+ if (attributes == null)
+ throw new IllegalArgumentException("Attributes cannot be null");
+ this.attributes = attributes;
+ }
+
+ @Override
+ public int size() {
+ return attributes.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return attributes.size() == 0;
+ }
+
+ @Override
+ public Enumeration<String> keys() {
+ NamingEnumeration<String> namingEnumeration = attributes.getIDs();
+ return new Enumeration<String>() {
+
+ @Override
+ public boolean hasMoreElements() {
+ return namingEnumeration.hasMoreElements();
+ }
+
+ @Override
+ public String nextElement() {
+ return namingEnumeration.nextElement();
+ }
+
+ };
+ }
+
+ @Override
+ public Enumeration<Object> elements() {
+ NamingEnumeration<String> namingEnumeration = attributes.getIDs();
+ return new Enumeration<Object>() {
+
+ @Override
+ public boolean hasMoreElements() {
+ return namingEnumeration.hasMoreElements();
+ }
+
+ @Override
+ public Object nextElement() {
+ String key = namingEnumeration.nextElement();
+ return get(key);
+ }
+
+ };
+ }
+
+ @Override
+ /** @returns a <code>String</code> or <code>String[]</code> */
+ public Object get(Object key) {
+ try {
+ if (key == null)
+ throw new IllegalArgumentException("Key cannot be null");
+ Attribute attr = attributes.get(key.toString());
+ if (attr == null)
+ return null;
+ if (attr.size() == 0)
+ throw new IllegalStateException("There must be at least one value");
+ else if (attr.size() == 1) {
+ return attr.get().toString();
+ } else {// multiple
+ String[] res = new String[attr.size()];
+ for (int i = 0; i < attr.size(); i++) {
+ Object value = attr.get();
+ if (value == null)
+ throw new RuntimeException("Values cannot be null");
+ res[i] = attr.get(i).toString();
+ }
+ return res;
+ }
+ } catch (NamingException e) {
+ throw new RuntimeException("Cannot get value for " + key, e);
+ }
+ }
+
+ @Override
+ public Object put(String key, Object value) {
+ if (key == null)
+ throw new IllegalArgumentException("Key cannot be null");
+ if (value == null)
+ throw new IllegalArgumentException("Value cannot be null");
+
+ Object oldValue = get(key);
+ Attribute attr = attributes.get(key);
+ if (attr == null) {
+ attr = new BasicAttribute(key);
+ attributes.put(attr);
+ }
+
+ if (value instanceof String[]) {
+ String[] values = (String[]) value;
+ // clean additional values
+ for (int i = values.length; i < attr.size(); i++)
+ attr.remove(i);
+ // set values
+ for (int i = 0; i < values.length; i++) {
+ attr.set(i, values[i]);
+ }
+ } else {
+ if (attr.size() != 1)
+ throw new IllegalArgumentException("Attribute " + key + " is multi-valued");
+ attr.set(0, value.toString());
+ }
+ return oldValue;
+ }
+
+ @Override
+ public Object remove(Object key) {
+ if (key == null)
+ throw new IllegalArgumentException("Key cannot be null");
+ Object oldValue = get(key);
+ if (oldValue == null)
+ return null;
+ return attributes.remove(key.toString());
+ }
+
+ /**
+ * Copy the <b>content</b> of an {@link javax.naming.Attributes} to the
+ * provided {@link Dictionary}.
+ */
+ public static void copy(Attributes attributes, Dictionary<String, Object> dictionary) {
+ AttributesDictionary ad = new AttributesDictionary(attributes);
+ Enumeration<String> keys = ad.keys();
+ while (keys.hasMoreElements()) {
+ String key = keys.nextElement();
+ dictionary.put(key, ad.get(key));
+ }
+ }
+
+ /**
+ * Copy a {@link Dictionary} into an {@link javax.naming.Attributes}.
+ */
+ public static void copy(Dictionary<String, Object> dictionary, Attributes attributes) {
+ AttributesDictionary ad = new AttributesDictionary(attributes);
+ Enumeration<String> keys = dictionary.keys();
+ while (keys.hasMoreElements()) {
+ String key = keys.nextElement();
+ ad.put(key, dictionary.get(key));
+ }
+ }
+}
--- /dev/null
+package org.argeo.util.naming;
+
+import static org.argeo.osgi.useradmin.LdifName.dn;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import javax.naming.InvalidNameException;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.osgi.useradmin.UserDirectoryException;
+
+/** Basic LDIF parser. */
+public class LdifParser {
+ private final static Log log = LogFactory.getLog(LdifParser.class);
+
+ protected Attributes addAttributes(SortedMap<LdapName, Attributes> res,
+ int lineNumber, LdapName currentDn, Attributes currentAttributes) {
+ try {
+ Rdn nameRdn = currentDn.getRdn(currentDn.size() - 1);
+ Attribute nameAttr = currentAttributes.get(nameRdn.getType());
+ if (nameAttr == null)
+ currentAttributes.put(nameRdn.getType(), nameRdn.getValue());
+ else if (!nameAttr.get().equals(nameRdn.getValue()))
+ throw new UserDirectoryException("Attribute "
+ + nameAttr.getID() + "=" + nameAttr.get()
+ + " not consistent with DN " + currentDn
+ + " (shortly before line " + lineNumber
+ + " in LDIF file)");
+ Attributes previous = res.put(currentDn, currentAttributes);
+ if (log.isTraceEnabled())
+ log.trace("Added " + currentDn);
+ return previous;
+ } catch (NamingException e) {
+ throw new UserDirectoryException("Cannot add " + currentDn, e);
+ }
+ }
+
+ public SortedMap<LdapName, Attributes> read(InputStream in) throws IOException {
+ SortedMap<LdapName, Attributes> res = new TreeMap<LdapName, Attributes>();
+ try {
+ List<String> lines = IOUtils.readLines(in);
+ // add an empty new line since the last line is not checked
+ if (!lines.get(lines.size() - 1).equals(""))
+ lines.add("");
+
+ LdapName currentDn = null;
+ Attributes currentAttributes = null;
+ StringBuilder currentEntry = new StringBuilder();
+
+ readLines: for (int lineNumber = 0; lineNumber < lines.size(); lineNumber++) {
+ String line = lines.get(lineNumber);
+ boolean isLastLine = false;
+ if (lineNumber == lines.size() - 1)
+ isLastLine = true;
+ if (line.startsWith(" ")) {
+ currentEntry.append(line.substring(1));
+ if (!isLastLine)
+ continue readLines;
+ }
+
+ if (currentEntry.length() != 0 || isLastLine) {
+ // read previous attribute
+ StringBuilder attrId = new StringBuilder(8);
+ boolean isBase64 = false;
+ readAttrId: for (int i = 0; i < currentEntry.length(); i++) {
+ char c = currentEntry.charAt(i);
+ if (c == ':') {
+ if (i + 1 < currentEntry.length()
+ && currentEntry.charAt(i + 1) == ':')
+ isBase64 = true;
+ currentEntry.delete(0, i + (isBase64 ? 2 : 1));
+ break readAttrId;
+ } else {
+ attrId.append(c);
+ }
+ }
+
+ String attributeId = attrId.toString();
+ String cleanValueStr = currentEntry.toString().trim();
+ Object attributeValue = isBase64 ? Base64
+ .decodeBase64(cleanValueStr) : cleanValueStr;
+
+ // manage DN attributes
+ if (attributeId.equals(dn.name()) || isLastLine) {
+ if (currentDn != null) {
+ //
+ // ADD
+ //
+ Attributes previous = addAttributes(res,
+ lineNumber, currentDn, currentAttributes);
+ if (previous != null) {
+ log.warn("There was already an entry with DN "
+ + currentDn
+ + ", which has been discarded by a subsequent one.");
+ }
+ }
+
+ if (attributeId.equals(dn.name()))
+ try {
+ currentDn = new LdapName(
+ attributeValue.toString());
+ currentAttributes = new BasicAttributes(true);
+ } catch (InvalidNameException e) {
+ log.error(attributeValue
+ + " not a valid DN, skipping the entry.");
+ currentDn = null;
+ currentAttributes = null;
+ }
+ }
+
+ // store attribute
+ if (currentAttributes != null) {
+ Attribute attribute = currentAttributes
+ .get(attributeId);
+ if (attribute == null) {
+ attribute = new BasicAttribute(attributeId);
+ currentAttributes.put(attribute);
+ }
+ attribute.add(attributeValue);
+ }
+ currentEntry = new StringBuilder();
+ }
+ currentEntry.append(line);
+ }
+ } finally {
+ IOUtils.closeQuietly(in);
+ }
+ return res;
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.util.naming;
+
+import static org.argeo.osgi.useradmin.LdifName.dn;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
+
+import org.apache.commons.codec.binary.Base64;
+import org.argeo.osgi.useradmin.UserDirectoryException;
+
+/** Basic LDIF writer */
+public class LdifWriter {
+ private final Writer writer;
+
+ /** Writer must be closed by caller */
+ public LdifWriter(Writer writer) {
+ this.writer = writer;
+ }
+
+ /** Stream must be closed by caller */
+ public LdifWriter(OutputStream out) {
+ this(new OutputStreamWriter(out));
+ }
+
+ public void writeEntry(LdapName name, Attributes attributes) throws IOException {
+ try {
+ // check consistency
+ Rdn nameRdn = name.getRdn(name.size() - 1);
+ Attribute nameAttr = attributes.get(nameRdn.getType());
+ if (!nameAttr.get().equals(nameRdn.getValue()))
+ throw new UserDirectoryException(
+ "Attribute " + nameAttr.getID() + "=" + nameAttr.get() + " not consistent with DN " + name);
+
+ writer.append(dn.name() + ":").append(name.toString()).append('\n');
+ Attribute objectClassAttr = attributes.get("objectClass");
+ if (objectClassAttr != null)
+ writeAttribute(objectClassAttr);
+ for (NamingEnumeration<? extends Attribute> attrs = attributes.getAll(); attrs.hasMore();) {
+ Attribute attribute = attrs.next();
+ if (attribute.getID().equals(dn.name()) || attribute.getID().equals("objectClass"))
+ continue;// skip DN attribute
+ writeAttribute(attribute);
+ }
+ writer.append('\n');
+ writer.flush();
+ } catch (NamingException e) {
+ throw new UserDirectoryException("Cannot write LDIF", e);
+ }
+ }
+
+ protected void writeAttribute(Attribute attribute) throws NamingException, IOException {
+ for (NamingEnumeration<?> attrValues = attribute.getAll(); attrValues.hasMore();) {
+ Object value = attrValues.next();
+ if (value instanceof byte[]) {
+ String encoded = Base64.encodeBase64String((byte[]) value);
+ writer.append(attribute.getID()).append("::").append(encoded).append('\n');
+ } else {
+ writer.append(attribute.getID()).append(':').append(value.toString()).append('\n');
+ }
+ }
+ }
+}
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">\r
\r
<!-- REFERENCES -->\r
- <reference id="secureLogger" interface="org.argeo.ArgeoLogger"\r
+ <reference id="secureLogger" interface="org.argeo.node.ArgeoLogger"\r
cardinality="0..1" />\r
\r
<reference id="nodeRepository" interface="javax.jcr.Repository"\r
import java.util.ArrayList;
-import org.argeo.ArgeoLogger;
+import org.argeo.node.ArgeoLogger;
import org.argeo.security.ui.SecurityUiPlugin;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.LabelProvider;
import java.util.LinkedList;
import java.util.List;
-import org.argeo.ArgeoLogListener;
+import org.argeo.node.ArgeoLogListener;
import org.eclipse.jface.viewers.ILazyContentProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import java.util.ArrayList;
-import org.argeo.ArgeoLogListener;
-import org.argeo.ArgeoLogger;
+import org.argeo.node.ArgeoLogListener;
+import org.argeo.node.ArgeoLogger;
import org.argeo.security.ui.SecurityUiPlugin;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.LabelProvider;
+++ /dev/null
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * 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.argeo;
-
-/** Framework agnostic interface for log notifications */
-public interface ArgeoLogListener {
- /**
- * Appends a log
- *
- * @param username
- * authentified user, null for anonymous
- * @param level
- * INFO, DEBUG, WARN, etc. (logging framework specific)
- * @param category
- * hierarchy (logging framework specific)
- * @param thread
- * name of the thread which logged this message
- * @param msg
- * any object as long as its toString() method returns the
- * message
- * @param the
- * exception in log4j ThrowableStrRep format
- */
- public void appendLog(String username, Long timestamp, String level,
- String category, String thread, Object msg, String[] exception);
-}
+++ /dev/null
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * 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.argeo;
-
-/**
- * Logging framework agnostic identifying a logging service, to which one can
- * register
- */
-public interface ArgeoLogger {
- /**
- * Register for events by threads with the same authentication (or all
- * threads if admin)
- */
- public void register(ArgeoLogListener listener,
- Integer numberOfPreviousEvents);
-
- /**
- * For admin use only: register for all users
- *
- * @param listener
- * the log listener
- * @param numberOfPreviousEvents
- * the number of previous events to notify
- * @param everything
- * if true even anonymous is logged
- */
- public void registerForAll(ArgeoLogListener listener,
- Integer numberOfPreviousEvents, boolean everything);
-
- public void unregister(ArgeoLogListener listener);
-
- public void unregisterForAll(ArgeoLogListener listener);
-}
+++ /dev/null
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * 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.argeo.util;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Locale;
-
-import javax.security.auth.callback.LanguageCallback;
-
-import org.argeo.ArgeoException;
-
-/** Choose in a list of locales. TODO: replace with {@link LanguageCallback} */
-public class LocaleChoice {
- private final List<Locale> locales;
-
- private Integer selectedIndex = null;
- private final Integer defaultIndex;
-
- public LocaleChoice(List<Locale> locales, Locale defaultLocale) {
- Integer defaultIndex = null;
- this.locales = Collections.unmodifiableList(locales);
- for (int i = 0; i < locales.size(); i++)
- if (locales.get(i).equals(defaultLocale))
- defaultIndex = i;
-
- // based on language only
- if (defaultIndex == null)
- for (int i = 0; i < locales.size(); i++)
- if (locales.get(i).getLanguage().equals(defaultLocale.getLanguage()))
- defaultIndex = i;
-
- if (defaultIndex == null)
- throw new ArgeoException("Default locale " + defaultLocale + " is not in available locales " + locales);
- this.defaultIndex = defaultIndex;
-
- this.selectedIndex = defaultIndex;
- }
-
- /**
- * Convenience constructor based on a comma separated list of iso codes (en,
- * en_US, fr_CA, etc.). Default selection is default locale.
- */
- public LocaleChoice(String locales, Locale defaultLocale) {
- this(asLocaleList(locales), defaultLocale);
- }
-
- public String[] getSupportedLocalesLabels() {
- String[] labels = new String[locales.size()];
- for (int i = 0; i < locales.size(); i++) {
- Locale locale = locales.get(i);
- if (locale.getCountry().equals(""))
- labels[i] = locale.getDisplayLanguage(locale) + " [" + locale.getLanguage() + "]";
- else
- labels[i] = locale.getDisplayLanguage(locale) + " (" + locale.getDisplayCountry(locale) + ") ["
- + locale.getLanguage() + "_" + locale.getCountry() + "]";
-
- }
- return labels;
- }
-
- public Locale getSelectedLocale() {
- if (selectedIndex == null)
- return null;
- return locales.get(selectedIndex);
- }
-
- public void setSelectedIndex(Integer selectedIndex) {
- this.selectedIndex = selectedIndex;
- }
-
- public Integer getSelectedIndex() {
- return selectedIndex;
- }
-
- public Integer getDefaultIndex() {
- return defaultIndex;
- }
-
- public List<Locale> getLocales() {
- return locales;
- }
-
- public Locale getDefaultLocale() {
- return locales.get(getDefaultIndex());
- }
-
- /** Returns null if argument is null. */
- public static List<Locale> asLocaleList(Object locales) {
- if (locales == null)
- return null;
- ArrayList<Locale> availableLocales = new ArrayList<Locale>();
- String[] codes = locales.toString().split(",");
- for (int i = 0; i < codes.length; i++) {
- String code = codes[i];
- // variant not supported
- int indexUnd = code.indexOf("_");
- Locale locale;
- if (indexUnd > 0) {
- String language = code.substring(0, indexUnd);
- String country = code.substring(indexUnd + 1);
- locale = new Locale(language, country);
- } else {
- locale = new Locale(code);
- }
- availableLocales.add(locale);
- }
- return availableLocales;
- }
-
- public static void main(String[] args) {
- for (String isoL : Locale.getISOLanguages()) {
- Locale locale = new Locale(isoL);
- System.out.println(isoL + "\t" + locale.getDisplayLanguage() + "\t" + locale.getDisplayLanguage(locale));
- }
- }
-
-}