You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@marmotta.apache.org by ss...@apache.org on 2013/02/22 16:21:36 UTC

[31/37] MARMOTTA-105: refactoring of packages in remaining platform modules

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/69cbd57a/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/api/UserConfigurationService.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/api/UserConfigurationService.java b/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/api/UserConfigurationService.java
new file mode 100644
index 0000000..54e8da4
--- /dev/null
+++ b/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/api/UserConfigurationService.java
@@ -0,0 +1,99 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * 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.apache.marmotta.platform.user.api;
+
+import org.apache.marmotta.platform.user.model.UserAccount;
+
+import java.util.List;
+
+/**
+ * Add file description here!
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public interface UserConfigurationService {
+
+
+    /**
+     * Check whether the given configuration is set for the given user.
+     *
+     * @param user
+     * @param key
+     * @return
+     */
+    public boolean isUserConfigurationSet(UserAccount user, String key);
+
+    /**
+     * Get the configuration for the given user and key. If there is no such configuration, a new one is
+     * created with empty value (returns null).
+     *
+     * @param user  the user for whom to get the configuration
+     * @param key  unique configuration key for lookup
+     * @return a configuration object with either the configured value or null as value
+     */
+    public String getUserConfiguration(UserAccount user, String key);
+
+    /**
+     * Get the configuration for the given user and key. If there is no such configuration, a new one is
+     * created using the provided defaultValue as string value.
+     *
+     * @param user  the user for whom to get the configuration
+     * @param key unique configuration key for lookup
+     * @param defaultValue default value if configuration not found
+     * @return a configuration object with either the configured value or defaultValue
+     */
+    public String getUserConfiguration(UserAccount user, String key, String defaultValue);
+
+
+    /**
+     * Set the configuration "key" to the string value "value".
+     * @param key
+     * @param value
+     */
+    public void setUserConfiguration(UserAccount user, String key, String value);
+
+    /**
+     * Set the configuration "key" to the string value "value".
+     * @param key
+     * @param values
+     */
+    public void setUserListConfiguration(UserAccount user, String key, List<String> values);
+
+
+    /**
+     * Return the list configuration value of the given key for the given user. If there is
+     * no value for the key, returns the empty list.
+     *
+     * @param user
+     */
+    public List<Object> getUserListConfiguration(UserAccount user, String key);
+
+    /**
+     * Return the list configuration value of the given key for the given user. Returns the
+     * given defaultValue if no configuration is found for the given key.
+     *
+     * @param user
+     */
+    public List<Object> getUserListConfiguration(UserAccount user, String key, List<Object> defaultValue);
+
+    /**
+     * Remove the user configuration identified by "key" from the database.
+     * @param key
+     */
+    public void removeUserConfiguration(UserAccount user, String key);
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/69cbd57a/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/filters/LMFAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/filters/LMFAuthenticationFilter.java b/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/filters/LMFAuthenticationFilter.java
new file mode 100644
index 0000000..78b0043
--- /dev/null
+++ b/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/filters/LMFAuthenticationFilter.java
@@ -0,0 +1,201 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * 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.apache.marmotta.platform.user.filters;
+
+import org.apache.marmotta.platform.user.api.AuthenticationService;
+import org.apache.marmotta.commons.sesame.model.Namespaces;
+import org.apache.marmotta.platform.core.api.config.ConfigurationService;
+import org.apache.marmotta.platform.core.api.modules.LMFHttpFilter;
+import org.apache.marmotta.platform.core.api.user.UserService;
+import org.apache.marmotta.platform.core.exception.UserExistsException;
+import org.apache.marmotta.platform.core.exception.security.AccessDeniedException;
+import org.jboss.resteasy.spi.UnhandledException;
+import org.openrdf.model.URI;
+import org.slf4j.Logger;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+import static org.apache.commons.codec.binary.Base64.decodeBase64;
+
+/**
+ * This filter implements HTTB Basic Authentication support for the LMF. It serves two purposes:
+ * <ul>
+ *     <li>carrying out HTTP Basic Authentication when an "Authorization" header is present</li>
+ *     <li>sending an HTTP authorization request in case one of the services in the chain threw an AccessDeniedException</li>
+ * </ul>
+ *
+ * In case security is enabled, it listens for the presence of an "Authorization" header, parses it according to HTTP Basic Authentication
+ * (Base64 decoding and splitting username/password at ":") and tries to authenticate with the given
+ * credentials using the LMF AuthenticationService.
+ * <ul>
+ * <li>In case authentication succeeds, it sets the attributes
+ *   user.name and user.roles in the request so that further filters/services can make use of the
+ *   authentication information, and it sets the current user for all activities carried out in the thread.</li>
+ * <li>In case authentication fails, no user information is added to the request.</li>
+ * </ul>
+ * The filter also listens for {@link org.apache.marmotta.platform.core.exception.security.AccessDeniedException} thrown by
+ * subsequent filters or servlets in the chain, in which case it returns an HTTP authorization request to the
+ * client. In particular, this functionality is used by the LMFAccessControlFilter to restrict access to
+ * services based on security profiles.
+ * <p/>
+ * @see UserService
+ * 
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+@ApplicationScoped
+public class LMFAuthenticationFilter implements LMFHttpFilter {
+
+    @Inject
+    private Logger log;
+
+    @Inject
+    private ConfigurationService configurationService;
+
+    @Inject
+    private UserService userService;
+
+    @Inject
+    private AuthenticationService authenticationService;
+
+    /**
+     * Initialise authentication filter
+     */
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+        log.info("LMF Authentication Filter starting up; user authentication is {}",configurationService.getBooleanConfiguration("security.enabled",true)?"enabled":"disabled");
+    }
+
+
+    /**
+     * Return the pattern (regular expression) that a request URI (relative to the LMF base URI) has to match
+     * before triggering this filter.
+     *
+     * @return
+     */
+    @Override
+    public String getPattern() {
+        return "^/.*";
+    }
+
+    /**
+     * Return the priority of the filter. Filters that need to be executed before anything else should return
+     * PRIO_FIRST, filters that need to be executed last in the chain should return PRIO_LAST, all other filters
+     * something inbetween (e.g. PRIO_MIDDLE).
+     *
+     * @return
+     */
+    @Override
+    public int getPriority() {
+        return PRIO_AUTH;
+    }
+
+    /**
+     * Check for the presence of a "Authorization" header in the request header and authorize the user if yes.
+     * Sets the attributes "user.name" and "user.roles" in the request for further processing.
+     */
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+        if(configurationService.getBooleanConfiguration("security.enabled",true)) {
+
+            HttpServletRequest httpRequest = (HttpServletRequest)request;
+
+            // check whether authentication information has been sent with the request
+
+            try {
+                String authorization = httpRequest.getHeader("Authorization");
+                if (authorization != null) {
+                    boolean authSuccess = false;
+                    String login = Namespaces.ANONYMOUS_LOGIN;
+                    if (authorization.startsWith("Basic ")) {
+                        String credentialsBase64 = authorization.split(" ")[1];
+                        String credentialsPlain = new String(decodeBase64(credentialsBase64));
+                        String[] credentials = credentialsPlain.split(":");
+                        if (credentials.length == 2) {
+                            login = credentials[0];
+                            String passwd = credentials[1];
+
+                            if (authenticationService.authenticateUser(login, passwd)) {
+                                authSuccess = true;
+                                httpRequest.setAttribute("user.name", login);
+                                httpRequest.setAttribute("user.roles", authenticationService.listUserRoles(login));
+                                URI user = userService.getUser(login);
+                                if (user == null) {
+                                    try {
+                                        user = userService.createUser(login);
+                                    } catch (UserExistsException e) {
+                                    }
+                                }
+                                userService.setCurrentUser(user);
+                            }
+                        }
+                    }
+                    if (!authSuccess && !login.equals(Namespaces.ANONYMOUS_LOGIN)) {
+                        // Apparently wrong username/passwd: ask for the correct one
+                        throw new AccessDeniedException();
+                    }
+                }
+
+                chain.doFilter(request,response);
+            } catch(AccessDeniedException ex) {
+                build401Response(response);
+            } catch (UnhandledException ue) {
+                // This is to handle AccessDeniedExeptions in REST-Webservices
+                if (ue.getCause().getClass().equals(AccessDeniedException.class)) {
+                    build401Response(response);
+                } else
+                    throw ue;
+            } finally {
+                userService.clearCurrentUser();
+            }
+        } else {
+            chain.doFilter(request,response);
+        }
+    }
+
+    private void build401Response(ServletResponse response) {
+        // access denied; request authentication
+        HttpServletResponse httpResponse = (HttpServletResponse)response;
+        httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+
+        String authMethod = "Basic";
+        if ("BASIC".equalsIgnoreCase(configurationService.getStringConfiguration("security.method", authMethod))) {
+            authMethod = "Basic";
+            //                } else if("DIGEST".equalsIgnoreCase(configurationService.getStringConfiguration("security.method"))) {
+            //                    authMethod = "Digest";
+        }
+        String authRealm  = configurationService.getStringConfiguration("security.realm","Linked Media Framework");
+
+        httpResponse.setHeader("WWW-Authenticate",authMethod + " realm=\""+authRealm+"\"");
+    }
+
+    /**
+     * Destroy authentication filter
+     */
+    @Override
+    public void destroy() {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/69cbd57a/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/model/UserAccount.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/model/UserAccount.java b/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/model/UserAccount.java
new file mode 100644
index 0000000..d042e40
--- /dev/null
+++ b/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/model/UserAccount.java
@@ -0,0 +1,183 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * 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.apache.marmotta.platform.user.model;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.marmotta.commons.util.HashUtils;
+
+/**
+ * User: Stephanie Stroka
+ * Date: 18.05.2011
+ * Time: 11:29:17
+ */
+
+public class UserAccount implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Enum of avalable password-hash algorithms.
+     *
+     * @author Jakob Frank <ja...@salzburgresearch.at>
+     *
+     */
+    public static enum PasswordHash {
+        PLAIN {
+            @Override
+            protected String hash(String in) {
+                return in;
+            }
+        },
+        MD5 {
+            @Override
+            protected String hash(String in) {
+                return HashUtils.md5sum(in);
+            }
+        },
+        SHA1 {
+            @Override
+            protected String hash(String in) {
+                return HashUtils.sha1(in);
+            }
+        };
+
+        public String encrypt(String passwd) {
+            return passwd == null ? null : ":" + this.toString().toLowerCase() + "::" + this.hash(passwd);
+        }
+
+        protected abstract String hash(String in);
+
+        private static final Pattern P = Pattern.compile(":(\\w+)::(.*)");
+
+        public static boolean checkPasswd(String encrypted, String passwd) {
+            if (encrypted != null && passwd != null) {
+                try {
+                    Matcher m = P.matcher(encrypted);
+                    if (m.matches()) {
+                        final PasswordHash h = PasswordHash.valueOf(m.group(1).toUpperCase());
+                        return encrypted.matches(h.encrypt(passwd));
+                    }
+                } catch (Exception e) {
+                }
+            }
+            return false;
+        }
+
+        public static PasswordHash getPasswordHash(String passwdHash) {
+            if (passwdHash != null) {
+                try {
+                    Matcher m = P.matcher(passwdHash);
+                    if (m.matches()) {
+                        final PasswordHash h = PasswordHash.valueOf(m.group(1).toUpperCase());
+                        return h;
+                    }
+                } catch (Exception e) {
+                }
+            }
+            return SHA1;
+        }
+    }
+
+
+    /* the user's credentials */
+    private String login;
+    private String  passwdHash;
+
+    /* the user's webId that points to their RDF user profile */
+    private String webId;
+
+    private Set<String>     roles;
+
+    public UserAccount() {
+        roles = new HashSet<String>();
+    }
+
+    public UserAccount(String login, String webId) {
+        this();
+        this.login = login;
+        this.webId = webId;
+    }
+
+    public String getLogin() {
+        return login;
+    }
+
+    public void setLogin(String login) {
+        this.login = login;
+    }
+
+    public String getPasswdHash() {
+        return passwdHash;
+    }
+
+    public void setPasswdHash(String passwdHash) {
+        this.passwdHash = passwdHash;
+    }
+
+    public boolean checkPasswd(String password) {
+        return PasswordHash.checkPasswd(getPasswdHash(), password);
+    }
+
+
+    public void setPasswd(PasswordHash alg, String passwd) {
+        this.passwdHash = alg.encrypt(passwd);
+    }
+
+    public String getWebId() {
+        return webId;
+    }
+
+    public void setWebId(String webId) {
+        this.webId = webId;
+    }
+
+
+    public Set<String> getRoles() {
+        return roles;
+    }
+
+    public void setRoles(Set<String> roles) {
+        this.roles = roles;
+    }
+
+    public void addRole(String role) {
+        this.roles.add(role);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        UserAccount that = (UserAccount) o;
+
+        if (login != null ? !login.equals(that.login) : that.login != null) return false;
+        if (webId != null ? !webId.equals(that.webId) : that.webId != null) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = login != null ? login.hashCode() : 0;
+        result = 31 * result + (webId != null ? webId.hashCode() : 0);
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/69cbd57a/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/services/AccountServiceImpl.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/services/AccountServiceImpl.java b/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/services/AccountServiceImpl.java
new file mode 100644
index 0000000..752a33e
--- /dev/null
+++ b/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/services/AccountServiceImpl.java
@@ -0,0 +1,292 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * 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.apache.marmotta.platform.user.services;
+
+import org.apache.marmotta.platform.user.api.AccountService;
+import org.apache.marmotta.platform.user.model.UserAccount;
+import org.apache.marmotta.platform.user.model.UserAccount.PasswordHash;
+import com.google.common.base.Preconditions;
+import org.apache.marmotta.platform.core.api.config.ConfigurationService;
+import org.apache.marmotta.platform.core.api.user.UserService;
+import org.apache.marmotta.platform.core.events.ConfigurationChangedEvent;
+import org.apache.marmotta.platform.core.events.SystemStartupEvent;
+import org.apache.marmotta.platform.core.exception.UserExistsException;
+import org.apache.marmotta.platform.core.model.user.KiWiUser;
+import org.apache.marmotta.platform.core.qualifiers.cache.LMFCache;
+import net.sf.ehcache.Ehcache;
+import net.sf.ehcache.Element;
+import org.apache.commons.lang.StringUtils;
+import org.apache.marmotta.commons.sesame.model.Namespaces;
+import org.apache.marmotta.kiwi.model.rdf.KiWiUriResource;
+import org.openrdf.model.Resource;
+import org.openrdf.model.URI;
+import org.slf4j.Logger;
+
+import javax.annotation.PostConstruct;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.event.Observes;
+import javax.inject.Inject;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@ApplicationScoped
+public class AccountServiceImpl implements AccountService {
+
+    @Inject
+    private Logger               log;
+
+    @Inject
+    private ConfigurationService configurationService;
+
+    @Inject
+    private UserService          userService;
+
+    @Inject
+    @LMFCache("user-cache")
+    private Ehcache              userCache;
+
+    private PasswordHash         hashAlgo;
+
+
+    public AccountServiceImpl() {
+        hashAlgo = PasswordHash.SHA1;
+    }
+
+    @PostConstruct
+    public void initialize() {
+        final String conf = configurationService.getStringConfiguration("security.password.hash", "SHA1").toUpperCase();
+        try {
+            hashAlgo = PasswordHash.valueOf(conf);
+        } catch (Exception e) {
+            hashAlgo = PasswordHash.SHA1;
+            log.warn("Invalid/unknown password hash algorithm: {}, falling back to {}", conf, hashAlgo);
+        }
+    }
+
+    public void systemStartup(@Observes SystemStartupEvent event) {
+        log.info("creating default system accounts ...");
+        createDefaultAccounts();
+    }
+
+    public void onConfigurationChange(@Observes ConfigurationChangedEvent event) {
+        if (event.containsChangedKey("security.password.hash")) {
+            initialize();
+        }
+    }
+
+    @Override
+    public void createDefaultAccounts() {
+        // Currently there is only one default account: admin
+        UserAccount account = getAccount(Namespaces.ADMIN_LOGIN);
+        if (account == null) {
+            Set<String> roles = new HashSet<String>(configurationService.getListConfiguration("user." + Namespaces.ADMIN_LOGIN + ".roles"));
+            account = createAccount(Namespaces.ADMIN_LOGIN);
+            account.setRoles(roles);
+            account.setPasswd(hashAlgo, configurationService.getStringConfiguration("user." + Namespaces.ADMIN_LOGIN + ".password"));
+            save(account);
+        }
+    }
+
+    @Override
+    public List<UserAccount> listAccounts() {
+        Set<String> logins = new HashSet<String>();
+        for(String key : configurationService.listConfigurationKeys("user")) {
+            String[] components = key.split("\\.");
+            if(components.length > 2 && "webid".equals(components[2])) {
+                logins.add(components[1]);
+            }
+        }
+
+        final List<UserAccount> list = new ArrayList<UserAccount>();
+        for(String login : logins) {
+            list.add(getAccount(login));
+        }
+
+
+        for (UserAccount userAccount : list) {
+            userCache.put(new Element(userAccount.getLogin(), userAccount));
+            userCache.put(new Element(userAccount.getWebId(), userAccount));
+        }
+        return list;
+    }
+
+    @Override
+    public List<UserAccount> listAccounts(String role) {
+        List<UserAccount> result = new ArrayList<UserAccount>();
+
+        for(UserAccount account : listAccounts()) {
+            if(account.getRoles().contains(role)) {
+                result.add(account);
+            }
+        }
+
+        return result;
+    }
+
+    @Override
+    public UserAccount createAccount(String login) {
+        return createAccount(login, null, null);
+    }
+
+    @Override
+    public UserAccount createAccount(String login, String firstName, String lastName) {
+        Preconditions.checkArgument(StringUtils.isNotBlank(login), "blank/empty login not allowed");
+
+        URI webid = userService.getUser(login);
+        if (webid == null) {
+            try {
+                webid = userService.createUser(login, firstName, lastName);
+            } catch (UserExistsException e) {
+                log.warn("User {} exists. This should not happen as it was checked 3 lines before!", login);
+                webid = userService.getUser(login);
+            }
+        }
+
+        if(webid instanceof KiWiUriResource) {
+            UserAccount account = new UserAccount(login, webid.stringValue());
+
+            save(account);
+
+            return account;
+        } else {
+            log.error("could not create user account, the backend is not KiWi");
+
+            return null;
+        }
+    }
+
+    private void save(UserAccount account) {
+        configurationService.setConfiguration("user."+account.getLogin()+".pwhash", account.getPasswdHash());
+        configurationService.setConfiguration("user."+account.getLogin()+".webid", account.getWebId());
+        configurationService.setListConfiguration("user." + account.getLogin() + ".roles", new ArrayList<String>(account.getRoles()));
+    }
+
+    @Override
+    public void deleteAccount(UserAccount account) {
+        for(String key : configurationService.listConfigurationKeys("user."+account.getLogin())) {
+            configurationService.removeConfiguration(key);
+        }
+        userCache.remove(account.getLogin());
+        userCache.remove(account.getWebId());
+    }
+
+    @Override
+    public UserAccount getAccount(String login) {
+        if (StringUtils.isBlank(login)) return null;
+        UserAccount account = null;
+        if (userCache != null && userCache.get(login) != null) {
+            account = (UserAccount) userCache.get(login).getObjectValue();
+        } else {
+            if (configurationService.isConfigurationSet("user."+login+".webid")) {
+                account = new UserAccount();
+
+                account.setLogin(login);
+                account.setPasswdHash(configurationService.getStringConfiguration("user."+login+".pwhash"));
+                account.setRoles(new HashSet<String>(configurationService.getListConfiguration("user."+login+".roles")));
+                account.setWebId(configurationService.getStringConfiguration("user."+login+".webid"));
+
+                userCache.put(new Element(account.getLogin(), account));
+                userCache.put(new Element(account.getWebId(), account));
+            } else {
+                log.info("UserAccount {} not found", login);
+            }
+        }
+        return account;
+    }
+
+    @Override
+    public UserAccount getAccount(URI resource) {
+        Preconditions.checkArgument(resource != null);
+
+        UserAccount account = null;
+        if (userCache != null && userCache.get(resource) != null) {
+            account = (UserAccount) userCache.get(resource).getObjectValue();
+        } else {
+            for(UserAccount a : listAccounts()) {
+                if(a.getWebId().equals(resource.stringValue())) {
+                    account = a;
+                    break;
+                }
+            }
+            if (account != null) {
+                userCache.put(new Element(account.getLogin(), account));
+                userCache.put(new Element(account.getWebId(), account));
+            } else {
+                log.warn("UserAccount {} not found", resource);
+            }
+        }
+        return account;
+    }
+
+    @Override
+    public UserAccount getAccount(KiWiUser user) {
+        Resource delegate = user.getDelegate();
+        if (delegate instanceof URI)
+            return getAccount((URI) delegate);
+        return null;
+    }
+
+    @Override
+    public UserAccount setPassword(UserAccount account, String passwd) {
+        account.setPasswd(hashAlgo, passwd);
+        save(account);
+        return account;
+    }
+
+    @Override
+    public boolean checkPassword(UserAccount account, String passwd) {
+        return account != null && account.checkPasswd(passwd);
+    }
+
+    @Override
+    public boolean checkPassword(String login, String passwd) {
+        return getAccount(login) != null && getAccount(login).checkPasswd(passwd);
+    }
+
+    @Override
+    public void setRoles(UserAccount account, Set<String> roles) {
+        account.setRoles(new HashSet<String>(roles));
+        save(account);
+    }
+
+    @Override
+    public Set<String> getRoles(UserAccount account) {
+        return account.getRoles();
+    }
+
+    @Override
+    public void addRole(UserAccount account, String role) {
+        account.addRole(role);
+        save(account);
+    }
+
+    @Override
+    public void removeRole(UserAccount account, String role) {
+        Set<String> roles = account.getRoles();
+        roles.remove(role);
+        account.setRoles(roles);
+        save(account);
+    }
+
+    @Override
+    public boolean hasRole(UserAccount account, String role) {
+        return account.getRoles().contains(role);
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/69cbd57a/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/services/AuthenticationServiceImpl.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/services/AuthenticationServiceImpl.java b/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/services/AuthenticationServiceImpl.java
new file mode 100644
index 0000000..e456977
--- /dev/null
+++ b/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/services/AuthenticationServiceImpl.java
@@ -0,0 +1,165 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * 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.apache.marmotta.platform.user.services;
+
+import org.apache.marmotta.platform.user.api.AccountService;
+import org.apache.marmotta.platform.user.api.AuthenticationProvider;
+import org.apache.marmotta.platform.user.api.AuthenticationService;
+import org.apache.marmotta.platform.user.model.UserAccount;
+import org.apache.marmotta.platform.core.api.config.ConfigurationService;
+import org.apache.marmotta.platform.core.events.ConfigurationChangedEvent;
+import org.apache.marmotta.platform.core.util.CdiUtils;
+import org.slf4j.Logger;
+
+import javax.annotation.PostConstruct;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.Any;
+import javax.enterprise.inject.Instance;
+import javax.inject.Inject;
+import javax.inject.Named;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A simple implementation of an authentication that stores plain-text passwords in the system configuration.
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+@ApplicationScoped
+public class AuthenticationServiceImpl implements AuthenticationService {
+
+    public static final String               DEFAULT_AUTH_PROVIDER_NAMED = "lmf";
+
+    @Inject
+    private Logger log;
+
+    @Inject
+    private AccountService accountService;
+
+    @Inject
+    private ConfigurationService configurationService;
+
+    @Inject @Any
+    private Instance<AuthenticationProvider> providers;
+
+    private AuthenticationProvider authenticationProvider;
+
+    @PostConstruct
+    protected void initialize() {
+        log.debug("initializing AuthenticationService");
+
+        final String prov = configurationService.getStringConfiguration("user.auth.provider", DEFAULT_AUTH_PROVIDER_NAMED);
+
+        Instance<AuthenticationProvider> selected = CdiUtils.selectNamed(providers, prov);
+        if (selected.isAmbiguous()) {
+            authenticationProvider = selected.iterator().next();
+            log.error("multiple candidates for AuthenticationProvider '{}' found. Chose randomly!", prov);
+        } else if (selected.isUnsatisfied()) {
+            log.error("no candidate for AuthenticationProvider '{}' found, falling back to default", prov);
+            authenticationProvider = CdiUtils.selectNamed(providers, DEFAULT_AUTH_PROVIDER_NAMED).iterator().next();
+        } else {
+            authenticationProvider = selected.get();
+        }
+    }
+
+    protected void onConfigurationChange(@Observes ConfigurationChangedEvent event) {
+        if (event.containsChangedKey("user.auth.provider")) {
+            initialize();
+        }
+    }
+
+    @Override
+    public Set<String> listAuthProviderNames() {
+        HashSet<String> pNames = new HashSet<String>();
+        for (AuthenticationProvider p : providers) {
+            Named ann = p.getClass().getAnnotation(Named.class);
+            if (ann != null) {
+                pNames.add(ann.value());
+            }
+        }
+        return pNames;
+    }
+
+
+    /**
+     * Authenticate the user with the given login and password. Returns true on success, false if the user does not
+     * exist or the passwords do not match.
+     *
+     * @param login    login of the user to authenticate
+     * @param password password of the user to authenticate
+     * @return true on success, false if the user does not exist or the passwords do not match.
+     */
+    @Override
+    public boolean authenticateUser(String login, String password) {
+        log.debug("AUTH {} with {}", login, authenticationProvider != null ? authenticationProvider.getClass().getSimpleName() : null);
+        return authenticationProvider.checkPassword(accountService.getAccount(login), password);
+    }
+
+
+    /**
+     * Change the password of the user with the given login to the given new password. The implementation may decide
+     * where to persist the password in a secure manner and whether to apply additional security like password hashing.
+     *
+     * @param login
+     * @param password
+     * @return
+     */
+    @Override
+    public void setUserPassword(String login, String password) {
+        final UserAccount a = accountService.getAccount(login);
+        authenticationProvider.updatePassword(a, password);
+    }
+
+    /**
+     * Return the roles that are assigned to the user (a list of strings that can be chosen by the administrator as
+     * needed).
+     *
+     * @param login login name of the user for whom to return the roles
+     * @return a list of strings with the role names currently assigned to the user
+     */
+    @Override
+    public Set<String> listUserRoles(String login) {
+        return accountService.getRoles(accountService.getAccount(login));
+    }
+
+
+    /**
+     * Add the role with the given name to the user with the given login.
+     *
+     * @param login the login name of the user with whom to associate roles
+     * @param role  the role name to associate with the user
+     */
+    @Override
+    public void addUserRole(String login, String role) {
+        final UserAccount a = accountService.getAccount(login);
+        accountService.addRole(a, role);
+    }
+
+    /**
+     * Remove the role with the given name from the user with the given login.
+     *
+     * @param login the login name of the user from whom to remove the role
+     * @param role  the role name to remove from the list of roles of the user
+     */
+    @Override
+    public void removeUserRole(String login, String role) {
+        final UserAccount a = accountService.getAccount(login);
+        accountService.removeRole(a, role);
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/69cbd57a/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/services/UserConfigurationServiceImpl.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/services/UserConfigurationServiceImpl.java b/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/services/UserConfigurationServiceImpl.java
new file mode 100644
index 0000000..c3f23de
--- /dev/null
+++ b/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/services/UserConfigurationServiceImpl.java
@@ -0,0 +1,178 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * 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.apache.marmotta.platform.user.services;
+
+import org.apache.marmotta.platform.user.api.UserConfigurationService;
+import org.apache.marmotta.platform.user.model.UserAccount;
+import com.google.common.base.Preconditions;
+import org.apache.marmotta.platform.core.api.config.ConfigurationService;
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.MapConfiguration;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.slf4j.Logger;
+
+import javax.annotation.PostConstruct;
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import java.io.File;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Add file description here!
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+@ApplicationScoped
+public class UserConfigurationServiceImpl implements UserConfigurationService {
+
+    @Inject
+    private Logger log;
+
+    @Inject
+    private ConfigurationService configurationService;
+
+    private HashMap<String, Configuration>   userConfigurations;
+
+
+    @PostConstruct
+    public void initialise() {
+        userConfigurations = new HashMap<String, Configuration>();
+    }
+
+    /*
+    * (non-Javadoc)
+    *
+    * @see kiwi.api.config.ConfigurationService#isUserConfigurationSet(kiwi.model.user.UserAccount,
+    * java.lang.String)
+    */
+    @Override
+    public boolean isUserConfigurationSet(UserAccount user, String key) {
+        Preconditions.checkNotNull(user);
+        Preconditions.checkNotNull(key);
+
+        return getUserConfiguration(user).containsKey(key);
+    }
+
+    @Override
+    public String getUserConfiguration(UserAccount user, String key, String defaultValue) {
+        Preconditions.checkNotNull(user);
+        Preconditions.checkNotNull(key);
+
+        return getUserConfiguration(user).getString(key, defaultValue);
+    }
+
+    @Override
+    public String getUserConfiguration(UserAccount user, String key) {
+        Preconditions.checkNotNull(user);
+        Preconditions.checkNotNull(key);
+
+        return getUserConfiguration(user).getString(key);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see
+     * kiwi.api.config.ConfigurationService#getUserListConfiguration(kiwi.model.user.UserAccount,
+     * java.lang.String)
+     */
+    @Override
+    public List<Object> getUserListConfiguration(UserAccount user, String key) {
+        Preconditions.checkNotNull(user);
+        Preconditions.checkNotNull(key);
+
+        return getUserListConfiguration(user, key, Collections.emptyList());
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see
+     * kiwi.api.config.ConfigurationService#getUserListConfiguration(kiwi.model.user.UserAccount,
+     * java.lang.String, java.util.List)
+     */
+    @Override
+    public List<Object> getUserListConfiguration(UserAccount user, String key, List<Object> defaultValue) {
+        Preconditions.checkNotNull(user);
+        Preconditions.checkNotNull(key);
+
+        return getUserConfiguration(user).getList(key, defaultValue);
+    }
+
+    @Override
+    public void removeUserConfiguration(UserAccount user, String key) {
+        Preconditions.checkNotNull(user);
+        Preconditions.checkNotNull(key);
+
+        getUserConfiguration(user).clearProperty(key);
+    }
+
+    @Override
+    public void setUserListConfiguration(UserAccount user, String key, List<String> values) {
+        Preconditions.checkNotNull(user);
+        Preconditions.checkNotNull(key);
+
+        getUserConfiguration(user).setProperty(key, values);
+    }
+
+    @Override
+    public void setUserConfiguration(UserAccount user, String key, String value) {
+        Preconditions.checkNotNull(user);
+        Preconditions.checkNotNull(key);
+
+        getUserConfiguration(user).setProperty(key, value);
+    }
+
+
+    public Configuration getUserConfiguration(UserAccount user) {
+        Configuration userConfig = userConfigurations.get(user.getLogin());
+        if (userConfig == null) {
+
+            String userConfigFile = configurationService.getConfiguration("kiwi.work.dir") + File.separator + "config" + File.separator + user.getLogin() + ".conf";
+
+            try {
+                File f = new File(userConfigFile);
+                if (f.exists()) {
+                    f.createNewFile();
+                }
+                userConfig = new PropertiesConfiguration(f);
+            } catch (Exception ex) {
+                log.error("could not create user configuration in file #0: #1", userConfigFile, ex.getMessage());
+                userConfig = new MapConfiguration(new HashMap<String, Object>());
+            }
+            userConfigurations.put(user.getLogin(), userConfig);
+        }
+        return userConfig;
+    }
+
+
+    public void save(UserAccount user) {
+        Configuration userConfig = getUserConfiguration(user);
+
+        if (userConfig instanceof PropertiesConfiguration) {
+            try {
+                ((PropertiesConfiguration) userConfig).save();
+            } catch (ConfigurationException e) {
+                log.error("could not save user configuration for user #0: #1", user.getLogin(), e.getMessage());
+            }
+        }
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/69cbd57a/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/services/auth/LMFAuthProviderImpl.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/services/auth/LMFAuthProviderImpl.java b/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/services/auth/LMFAuthProviderImpl.java
new file mode 100644
index 0000000..8389e55
--- /dev/null
+++ b/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/services/auth/LMFAuthProviderImpl.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * 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.apache.marmotta.platform.user.services.auth;
+
+import org.apache.marmotta.platform.user.api.AccountService;
+import org.apache.marmotta.platform.user.api.AuthenticationProvider;
+import org.apache.marmotta.platform.user.model.UserAccount;
+import org.apache.marmotta.platform.user.services.AuthenticationServiceImpl;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Default;
+import javax.inject.Inject;
+import javax.inject.Named;
+
+@ApplicationScoped
+@Named(AuthenticationServiceImpl.DEFAULT_AUTH_PROVIDER_NAMED)
+@Default
+public class LMFAuthProviderImpl implements AuthenticationProvider {
+
+    @Inject
+    private AccountService accountService;
+
+    @Override
+    public boolean checkPassword(UserAccount login, String passwd) {
+        return accountService.checkPassword(login, passwd);
+    }
+
+    @Override
+    public boolean updatePassword(UserAccount login, String newPasswd) {
+        accountService.setPassword(login, newPasswd);
+        return true;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/69cbd57a/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/services/auth/LdapAuthProvider.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/services/auth/LdapAuthProvider.java b/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/services/auth/LdapAuthProvider.java
new file mode 100644
index 0000000..720e691
--- /dev/null
+++ b/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/services/auth/LdapAuthProvider.java
@@ -0,0 +1,132 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * 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.apache.marmotta.platform.user.services.auth;
+
+import org.apache.marmotta.platform.user.api.AuthenticationProvider;
+import org.apache.marmotta.platform.user.model.UserAccount;
+import org.apache.marmotta.platform.core.api.config.ConfigurationService;
+import org.slf4j.Logger;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.naming.Context;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+import javax.naming.directory.ModificationItem;
+import java.util.Hashtable;
+import java.util.regex.Pattern;
+
+/**
+ * Authenticate LMF-Users against LDAP.
+ * 
+ * TODO: maybe switch to jldap (compile 'com.novell.ldap:jldap:4.3') which might also allow password
+ * change.
+ * TODO: password-update is currently not implemented.
+ * 
+ * <h3>Configuration Settings</h3>
+ * <dl>
+ * <dt>user.auth.ldap.server
+ * <dd>hostname/IP of the ldap-server (default: <b>localhost</b>)
+ * <dt>user.auth.ldap.port
+ * <dd>ldap server port (default: <b>389</b>)
+ * <dt>user.auth.ldap.dn
+ * <dd>Pattern to build the DN for auth. <code>{login}</code> will be replaced by the account
+ * name/login (default: <b>{login}</b>)
+ * </dl>
+ * 
+ * @author Jakob Frank <ja...@salzburgresearch.at>
+ * @author Daniel Trabe <da...@salzburgresearch.at>
+ * 
+ */
+@ApplicationScoped
+@Named(LdapAuthProvider.QUALIFIER)
+public class LdapAuthProvider implements AuthenticationProvider {
+
+    static final String          QUALIFIER   = "ldap";
+    static final String          CONF_SERVER = "user.auth." + QUALIFIER + ".server";
+    static final String          CONF_PORT   = "user.auth." + QUALIFIER + ".port";
+    static final String          CONF_DN     = "user.auth." + QUALIFIER + ".dn";
+
+
+    @Inject
+    private ConfigurationService configurationService;
+
+    @Inject
+    private Logger               log;
+
+    @Override
+    public boolean checkPassword(UserAccount login, String passwd) {
+        return login != null && login(login.getLogin(), passwd);
+    }
+
+    @Override
+    public boolean updatePassword(UserAccount login, String newPasswd) {
+        if (login == null) return false;
+        String username = login.getLogin();
+        log.trace("changePassword called for account: {}", username);
+
+        ModificationItem[] mod = new ModificationItem[1];
+        Attribute attr = new BasicAttribute("userpassword", newPasswd);
+        mod[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, attr);
+
+        final String dn = configurationService.getStringConfiguration(CONF_DN, "{login}")
+                .replaceAll(Pattern.quote("{login}"), username);
+        try {
+            // ctx.modifyAttributes(dn, mod);
+            // log.info("LDAP-Passwd update for {} successful ({})", username, dn);
+            // return true;
+        } catch (Exception e) {
+            log.info("LDAP-Passwd update for {} failed ({})", username, dn);
+        }
+        log.warn("LDAP-Passwd update not implemented");
+        return false;
+    }
+
+    private boolean login(String login, String secret) {
+        try {
+            // Set up the environment for creating the initial context
+            Hashtable<String, String> env = new Hashtable<String, String>();
+            env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
+            env.put(Context.PROVIDER_URL, String.format("ldap://%s:%d",
+                    configurationService.getStringConfiguration(CONF_SERVER, configurationService.getServerName()),
+                    configurationService.getIntConfiguration(CONF_PORT, 389)));
+
+            env.put(Context.SECURITY_AUTHENTICATION, "simple");
+            env.put(Context.SECURITY_PRINCIPAL, configurationService.getStringConfiguration(CONF_DN, "{login}")
+                    .replaceAll(Pattern.quote("{login}"), login));
+            env.put(Context.SECURITY_CREDENTIALS, secret);
+
+            // Create the initial context
+            DirContext ctx = new InitialDirContext(env);
+            // If retrieving the context worked, login was successful.
+            boolean result = ctx != null;
+
+            if (ctx != null) {
+                ctx.close();
+            }
+
+            log.trace("LDAP-Login successful for {}", login);
+            return result;
+        } catch (Exception e) {
+            log.info("LDAP-Login for {} failed: {}", login, e.getMessage());
+            return false;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/69cbd57a/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/webservices/UserManagementWebService.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/webservices/UserManagementWebService.java b/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/webservices/UserManagementWebService.java
new file mode 100644
index 0000000..07f140f
--- /dev/null
+++ b/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/webservices/UserManagementWebService.java
@@ -0,0 +1,316 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * 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.apache.marmotta.platform.user.webservices;
+
+import org.apache.marmotta.platform.user.api.AccountService;
+import org.apache.marmotta.platform.user.model.UserAccount;
+import org.apache.marmotta.commons.sesame.model.Namespaces;
+import org.apache.marmotta.commons.sesame.repository.ResourceUtils;
+import org.apache.marmotta.platform.core.api.config.ConfigurationService;
+import org.apache.marmotta.platform.core.api.triplestore.SesameService;
+import org.apache.commons.lang.StringUtils;
+import org.openrdf.model.Literal;
+import org.openrdf.model.Statement;
+import org.openrdf.model.URI;
+import org.openrdf.model.Value;
+import org.openrdf.repository.RepositoryConnection;
+import org.openrdf.repository.RepositoryException;
+import org.openrdf.repository.RepositoryResult;
+import org.slf4j.Logger;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+@Path("/users")
+public class UserManagementWebService {
+    private static final Pattern PROFILE_URI_PATTERN = Pattern.compile("^<([^>]+)>$");
+
+    @Inject
+    private Logger         log;
+
+    @Inject
+    private AccountService accountService;
+
+    @Inject
+    private ConfigurationService configurationService;
+
+    @Inject
+    private SesameService sesameService;
+
+    private List<String>         acceptedFoafProperties;
+
+    private static final List<String> RESERVED_LOGINS     = Arrays.asList("me", "login", "anonymous");
+
+    @PostConstruct
+    public void initialize() {
+        acceptedFoafProperties = configurationService.getListConfiguration("user.account.foaf.properties",
+                Arrays.asList("firstName", "nick", "lastName", "familyName", "givenName", "name", "title", "age", "mbox", "homepage"));
+    }
+
+    /**
+     * List users (that have the given role).
+     *
+     * @param role the required role (optional)
+     * @return an array of {@link org.apache.marmotta.platform.user.webservices.UserWebService.AccountPoJo}s containing users (that have the required role, if
+     *         role was given) (in JSON).
+     */
+    @GET
+    @Produces(Namespaces.MIME_TYPE_JSON)
+    public Response listUsers(@QueryParam("role") String role) {
+        final List<UserAccount> accounts;
+        if (role == null) {
+            accounts = accountService.listAccounts();
+        } else {
+            accounts = accountService.listAccounts(role);
+        }
+
+        final List<UserWebService.AccountPoJo> resp = new ArrayList<UserWebService.AccountPoJo>();
+        for (UserAccount userAccount : accounts) {
+            UserWebService.AccountPoJo apj = new UserWebService.AccountPoJo(userAccount.getLogin(), userAccount.getWebId());
+            apj.setRoles(userAccount.getRoles());
+            resp.add(apj);
+        }
+
+        return Response.ok(resp, Namespaces.MIME_TYPE_JSON).build();
+    }
+
+    /**
+     * Create a new user account (incl. user resource)
+     *
+     * @param login the account name / login name of the new user.
+     * @return the {@link org.apache.marmotta.platform.user.webservices.UserWebService.AccountPoJo} of the newly created user.
+     * @HTTP 409 if an account with the given login already exists
+     * @HTTP 400 if the login is a reserved keyword: [me, login, anonymous]
+     * @HTTP 500 on other errors.
+     */
+    @POST
+    @Path("/{login}")
+    public Response createUser(@PathParam("login") String login) {
+        if (accountService.getAccount(login) != null)
+            return Response.status(Status.CONFLICT).entity(String.format("'%s' already exists!", login)).build();
+
+        if (StringUtils.isBlank(login)) return Response.status(Status.BAD_REQUEST).entity("Provide a username").build();
+
+        // Must not create an account with a reserved username!
+        if (RESERVED_LOGINS.contains(login))
+            return Response.status(Status.BAD_REQUEST).entity(String.format("The following usernames are not allowed: %s", RESERVED_LOGINS)).build();
+
+        UserAccount a = accountService.createAccount(login);
+        if (a != null)
+            return getUser(login);
+
+        log.error("Creating an account for {} failed", login);
+        return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Sorry, don't know why").build();
+    }
+
+    /**
+     * Return the Account data of the requested login
+     *
+     * @param login the account requested
+     * @return an {@link org.apache.marmotta.platform.user.webservices.UserWebService.AccountPoJo} of the requested account
+     * @HTTP 404 if no such user exists.
+     */
+    @GET
+    @Path("/{login}")
+    @Produces(Namespaces.MIME_TYPE_JSON)
+    public Response getUser(@PathParam("login") String login) {
+        UserAccount account = accountService.getAccount(login);
+        if (account == null) return Response.status(Status.NOT_FOUND).entity(String.format("No login for '%s' found!", login)).build();
+
+        try {
+            RepositoryConnection conn = sesameService.getConnection();
+            try {
+                UserWebService.AccountPoJo apj = new UserWebService.AccountPoJo(account.getLogin(), account.getWebId());
+                apj.setRoles(account.getRoles());
+
+                RepositoryResult<Statement> triples = conn.getStatements(conn.getValueFactory().createURI(account.getWebId()),null,null,true);
+
+                while(triples.hasNext()) {
+                    Statement t = triples.next();
+
+                    String prop = t.getPredicate().stringValue();
+                    if (prop.startsWith(Namespaces.NS_FOAF)) {
+                        Value object = t.getObject();
+                        if (object instanceof URI) {
+                            apj.setFoaf(prop, String.format("<%s>", object));
+                        } else if (object instanceof Literal) {
+                            apj.setFoaf(prop, object.toString());
+                        }
+                    }
+                }
+
+                return Response.ok(apj, Namespaces.MIME_TYPE_JSON).build();
+            } finally {
+                conn.commit();
+                conn.close();
+            }
+        } catch(RepositoryException ex) {
+            return Response.status(Status.INTERNAL_SERVER_ERROR).entity(ex.getMessage()).build();
+        }
+    }
+
+    /**
+     * Delete the account with the given login.
+     *
+     * @param login the account to delete
+     * @param delFoaf if <code>true</code>, also delete the user profile (foaf)
+     * @return 200 ok on success
+     * @HTTP 404 if no such user exists
+     */
+    @DELETE
+    @Path("/{login}")
+    public Response deleteUser(@PathParam("login") String login, @QueryParam("deleteFoaf") @DefaultValue("false") boolean delFoaf) {
+        UserAccount account = accountService.getAccount(login);
+        if (account == null) return Response.status(Status.NOT_FOUND).entity(String.format("No login for '%s' found!", login)).build();
+
+        try {
+            RepositoryConnection conn = sesameService.getConnection();
+            try {
+                if (delFoaf && account.getWebId() != null) {
+                    // TODO: Remove only users foaf profile?
+                    conn.remove(conn.getValueFactory().createURI(account.getWebId()),null,null);
+                }
+
+                accountService.deleteAccount(account);
+                return Response.status(Status.OK).entity(String.format("login removed")).build();
+            } finally {
+                conn.commit();
+                conn.close();
+            }
+        } catch(RepositoryException ex) {
+            return Response.status(Status.INTERNAL_SERVER_ERROR).entity(ex.getMessage()).build();
+        }
+    }
+
+    /**
+     * Set the roles for the given account
+     *
+     * @param login the account
+     * @param roles <code>role</code> params of the roles to set
+     * @param roles2 <code>role[]</code> params of the roles to set
+     * @return the {@link org.apache.marmotta.platform.user.webservices.UserWebService.AccountPoJo} of the account after update
+     * @HTTP 404 if no such account exists.
+     */
+    @POST
+    @Path("/{login}/roles")
+    public Response setUserRoles(@PathParam("login") String login, @QueryParam("role") String[] roles, @QueryParam("role[]") String[] roles2) {
+        UserAccount account = accountService.getAccount(login);
+        if (account == null) return Response.status(Status.NOT_FOUND).entity(String.format("No login for '%s' found!", login)).build();
+
+        HashSet<String> roleSet = new HashSet<String>();
+        for (String role : roles) {
+            roleSet.add(role);
+        }
+        for (String role : roles2) {
+            roleSet.add(role);
+        }
+        accountService.setRoles(account, roleSet);
+
+        return getUser(login);
+    }
+
+    /**
+     * Set the password for the given account
+     *
+     * @param login the account to set the password for
+     * @param passwd the new password
+     * @return 200 OK on success
+     * @HTTP 404 if no such account exists
+     */
+    @POST
+    @Path("/{login}/password")
+    public Response setUserPassword(@PathParam("login") String login, @FormParam("password") String passwd) {
+        UserAccount account = accountService.getAccount(login);
+        if (account == null) return Response.status(Status.NOT_FOUND).entity(String.format("No login for '%s' found!", login)).build();
+
+        accountService.setPassword(account, passwd);
+
+        return Response.ok("Password updated").build();
+    }
+
+    /**
+     * Update/Save the user profile (foaf) for the given account
+     *
+     * @param login the user to modify
+     * @param formParams the user profile (foaf, without prefix) in
+     *            {@value at.newmedialab.sesame.commons.model.Namespaces#MIME_TYPE_FORM_URLENC}
+     * @return {@link org.apache.marmotta.platform.user.webservices.UserWebService.AccountPoJo} after the update in JSON
+     * @see UserWebService#post(MultivaluedMap)
+     * @HTTP 404 if no such user exists.
+     */
+    @POST
+    @Path("/{login}/profile")
+    public Response setUserProfile(@PathParam("login") String login, MultivaluedMap<String, String> formParams) {
+        UserAccount account = accountService.getAccount(login);
+        if (account == null) return Response.status(Status.NOT_FOUND).entity(String.format("No login for '%s' found!", login)).build();
+
+        try {
+            RepositoryConnection conn = sesameService.getConnection();
+
+            try {
+                String currentUser = account.getWebId();
+                for (String prop : formParams.keySet()) {
+                    if (!acceptedFoafProperties.contains(prop)) {
+                        continue;
+                    }
+
+                    String property = Namespaces.NS_FOAF + prop;
+                    URI p = conn.getValueFactory().createURI(property);
+                    URI u = conn.getValueFactory().createURI(currentUser);
+                    ResourceUtils.removeProperty(conn,u, property);
+                    String val = formParams.getFirst(prop);
+                    if (val != null && val.length() > 0) {
+                        Matcher m = PROFILE_URI_PATTERN.matcher(val);
+                        if (m.matches()) {
+                            URI o = conn.getValueFactory().createURI(m.group(1));
+                            conn.add(u,p,o,u);
+                        } else {
+                            Literal o = conn.getValueFactory().createLiteral(val.trim());
+                            conn.add(u,p,o,u);
+                        }
+                    }
+                }
+            } finally {
+                conn.commit();
+                conn.close();
+            }
+        } catch (RepositoryException e) {
+            // This must not happen!
+            return Response.serverError().entity(e).build();
+        }
+
+        return getUser(login);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/69cbd57a/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/webservices/UserWebService.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/webservices/UserWebService.java b/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/webservices/UserWebService.java
new file mode 100644
index 0000000..96c5b1b
--- /dev/null
+++ b/platform/marmotta-user/src/main/java/org/apache/marmotta/platform/user/webservices/UserWebService.java
@@ -0,0 +1,346 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * 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.apache.marmotta.platform.user.webservices;
+
+import org.apache.marmotta.platform.user.api.AccountService;
+import org.apache.marmotta.platform.user.model.UserAccount;
+import org.apache.marmotta.commons.sesame.model.Namespaces;
+import org.apache.marmotta.commons.sesame.repository.ResourceUtils;
+import org.apache.marmotta.platform.core.api.config.ConfigurationService;
+import org.apache.marmotta.platform.core.api.triplestore.SesameService;
+import org.apache.marmotta.platform.core.api.user.UserService;
+import org.apache.marmotta.platform.core.exception.security.AccessDeniedException;
+import org.openrdf.model.Literal;
+import org.openrdf.model.Statement;
+import org.openrdf.model.URI;
+import org.openrdf.model.Value;
+import org.openrdf.repository.RepositoryConnection;
+import org.openrdf.repository.RepositoryException;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+import javax.ws.rs.*;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import java.io.UnsupportedEncodingException;
+import java.net.URISyntaxException;
+import java.net.URLEncoder;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * User-Account related webservices, accessable by every user (each for his/her own data)
+ *
+ * @author Jakob Frank <ja...@salzburgresearch.at>
+ *
+ */
+@Path("/user")
+public class UserWebService {
+
+    private static final Pattern PROFILE_URI_PATTERN = Pattern.compile("^<([^>]+)>$");
+
+    @Inject
+    private ConfigurationService configurationService;
+
+    @Inject
+    private UserService          userService;
+
+    @Inject
+    private AccountService       accountService;
+
+    @Inject
+    private SesameService        sesameService;
+
+    private List<String>         acceptedFoafProperties;
+
+    @PostConstruct
+    public void initialize() {
+        acceptedFoafProperties = configurationService.getListConfiguration("user.account.foaf.properties",
+                Arrays.asList("firstName", "nick", "lastName", "familyName", "givenName", "name", "title", "age", "mbox", "homepage"));
+    }
+
+    /**
+     * Provide Account information about the currently logged in user (account)
+     *
+     * @return {@link AccountPoJo} of the current user in JSON
+     * @see AccountPoJo
+     */
+    @GET
+    @Path("/me")
+    @Produces(Namespaces.MIME_TYPE_JSON)
+    public Response get() {
+        return get(userService.getCurrentUser());
+    }
+
+    private Response get(URI user) {
+        if (userService.isAnonymous(user)) {
+            AccountPoJo apj = new AccountPoJo(Namespaces.ANONYMOUS_LOGIN, user.stringValue());
+            return Response.ok(apj, Namespaces.MIME_TYPE_JSON).location(java.net.URI.create(user.stringValue())).build();
+        }
+        try {
+            RepositoryConnection conn = sesameService.getConnection();
+            try {
+                final UserAccount a = accountService.getAccount(user);
+                if (a != null) {
+                    AccountPoJo apj = new AccountPoJo(a.getLogin(), a.getWebId());
+                    apj.setRoles(a.getRoles());
+
+                    for (Statement t : ResourceUtils.listOutgoing(conn,conn.getValueFactory().createURI(a.getWebId()))) {
+                        String prop = t.getPredicate().stringValue();
+                        if (prop.startsWith(Namespaces.NS_FOAF)) {
+                            Value object = t.getObject();
+                            if (object instanceof org.openrdf.model.URI) {
+                                apj.setFoaf(prop, String.format("<%s>", object));
+                            } else if (object instanceof Literal) {
+                                apj.setFoaf(prop, object.toString());
+                            }
+                        }
+                    }
+
+                    return Response.ok(apj, Namespaces.MIME_TYPE_JSON).location(java.net.URI.create(user.stringValue())).build();
+                }
+                return Response.status(Status.NOT_FOUND).entity("Could not find account data of " + user).build();
+            } finally {
+                conn.commit();
+                conn.close();
+            }
+        } catch (RepositoryException e) {
+            // This must not happen!
+            return Response.serverError().entity(e).build();
+        }
+
+    }
+
+    /**
+     * Update/Set the profile information (foaf) for the current user.
+     * Post-Body should contain the property=value mapping (propterty without foaf-prefix) for the
+     * profile.
+     *
+     * @param formParams the user profile (foaf, without prefix) in
+     *            {@value at.newmedialab.sesame.commons.model.Namespaces#MIME_TYPE_FORM_URLENC}
+     * @return {@link AccountPoJo} after the update in JSON
+     *
+     * @HTTP 403 When the current user is <code>anonymous</code>.
+     * @HTTP 500 If a {@link RepositoryException} occurs (which should not happen as no
+     *       namespaces are used here)
+     */
+    @POST
+    @Path("/me")
+    @Consumes(Namespaces.MIME_TYPE_FORM_URLENC)
+    public Response post(MultivaluedMap<String, String> formParams) {
+        final URI currentUser = userService.getCurrentUser();
+        if (userService.isAnonymous(currentUser)) return Response.status(Status.FORBIDDEN).entity("anonymous is read-only").build();
+
+        try {
+            RepositoryConnection conn = sesameService.getConnection();
+
+            try {
+                for (String prop : formParams.keySet()) {
+                    if (!acceptedFoafProperties.contains(prop)) {
+                        continue;
+                    }
+                    URI p = conn.getValueFactory().createURI(Namespaces.NS_FOAF + prop);
+
+                    conn.remove(currentUser,p,null);
+
+                    String val = formParams.getFirst(prop);
+                    if (val != null && val.length() > 0) {
+                        Matcher m = PROFILE_URI_PATTERN.matcher(val);
+                        if (m.matches()) {
+                            URI o = conn.getValueFactory().createURI(m.group(1));
+                            conn.add(currentUser, p, o, currentUser);
+                        } else {
+                            Literal o = conn.getValueFactory().createLiteral(val.trim());
+                            conn.add(currentUser, p, o, currentUser);
+                        }
+                    }
+
+                }
+                return get(currentUser);
+            } finally {
+                conn.commit();
+                conn.close();
+            }
+        } catch (RepositoryException e) {
+            // This must not happen!
+            return Response.serverError().entity(e).build();
+        }
+    }
+
+    /**
+     * Dummy to avoid exceptions if post body is empty.
+     *
+     * @see #post(MultivaluedMap)
+     * @return {@link AccountPoJo} of the current user in JSON
+     */
+    @POST
+    @Path("/me")
+    public Response post() {
+        return get();
+    }
+
+    /**
+     * Update/change the password for the current user.
+     *
+     * @param oldPwd the old (current) password.
+     * @param newPwd the new password
+     * @return 200 OK on success
+     * @HTTP 404 if the current account could not be loaded
+     * @HTTP 403 if the old pasword did not match
+     */
+    @POST
+    @Path("/me/passwd")
+    public Response passwd(@FormParam("oldPasswd") String oldPwd, @FormParam("newPasswd") String newPwd) {
+        final org.openrdf.model.URI currentUser = userService.getCurrentUser();
+        final UserAccount a = accountService.getAccount(currentUser);
+
+        if (a == null) return Response.status(Status.NOT_FOUND).entity(String.format("No account found for <%s>", currentUser)).build();
+
+        if (accountService.checkPassword(a, oldPwd)) {
+            accountService.setPassword(a, newPwd);
+            return Response.ok("Password changed").build();
+        } else
+            return Response.status(Status.FORBIDDEN).entity("password check failed").build();
+    }
+
+    /**
+     * Resolve/Redirect access to /user/* uris.
+     *
+     * @param login the login of the user to redirect to
+     * @param types header param of accepted mime-types
+     * @return a redirect to the user-resource in the resource service.
+     * @HTTP 404 if no such user exists.
+     * @HTTP 303 on success
+     * @HTTP 400 if no valid resource uri could be built with the login
+     * @HTTP 500 on other exceptions
+     */
+    @GET
+    @Path("/{login:[^#?]+}")
+    public Response getUser(@PathParam("login") String login, @HeaderParam("Accept") String types) {
+        try {
+            RepositoryConnection conn = sesameService.getConnection();
+            try {
+                final URI user = userService.getUser(login);
+                if (user == null) return Response.status(Status.NOT_FOUND).entity(String.format("User %s not found", login)).build();
+
+                java.net.URI u = new java.net.URI(configurationService.getServerUri() + "resource?uri=" + URLEncoder.encode(user.stringValue(), "utf-8"));
+
+                return Response.seeOther(u).header("Accept", types).build();
+            } finally {
+                conn.commit();
+                conn.commit();
+            }
+        } catch (URISyntaxException e) {
+            return Response.status(Status.BAD_REQUEST).entity(String.format("Invalid URI: %s", e.getMessage())).build();
+        } catch (UnsupportedEncodingException e) {
+            return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
+        } catch (RepositoryException e) {
+            return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
+        }
+    }
+
+    /**
+     * Throws a {@link AccessDeniedException} if currently no user is logged in (aka: current user
+     * is anonymous).
+     *
+     * @param ref the referer to redirect to
+     * @param logout set to true to log out (does currently nothing)
+     * @return a redirect to the referer url
+     * @throws AccessDeniedException if currently no user is logged in.
+     * @HTTP 303 if the user is already logged in (or <code>logout == true</code>)
+     */
+    @GET
+    @Path("/login")
+    public Response login(@HeaderParam("Referer") String ref, @QueryParam("logout") @DefaultValue("false") boolean logout,
+                          @QueryParam("user") String login) {
+        // Check whether we want to logout
+        if (logout) {
+            userService.setCurrentUser(userService.getAnonymousUser());
+            throw new AccessDeniedException();
+        }
+
+        // Anonymous cannot login
+        if (userService.isAnonymous(userService.getCurrentUser())) throw new AccessDeniedException();
+
+        // Check whether this is the right (desired) user
+        if (login != null && !userService.getCurrentUser().equals(userService.getUser(login))) throw new AccessDeniedException();
+
+        if (ref == null || "".equals(ref)) {
+            ref = configurationService.getServerUri() + configurationService.getStringConfiguration("kiwi.pages.startup");
+        }
+        return Response.seeOther(java.net.URI.create(ref)).build();
+    }
+
+    /**
+     * Wrapped AccountInformation for serialisation.
+     *
+     * @author Jakob Frank <ja...@salzburgresearch.at>
+     *
+     */
+    static class AccountPoJo {
+        private String              login, uri, roles[];
+        private Map<String, String> foaf;
+
+        public AccountPoJo(String login, String uri) {
+            this.login = login;
+            if (uri != null) {
+                this.uri = uri;
+            } else {
+                this.uri = null;
+            }
+            this.roles = new String[0];
+            this.foaf = new HashMap<String, String>();
+        }
+
+        public void setRoles(Set<String> roles) {
+            if (roles != null) {
+                this.roles = roles.toArray(new String[roles.size()]);
+            } else {
+                this.roles = new String[0];
+            }
+        }
+
+        public void setFoaf(String prop, String value) {
+            foaf.put(prop, value);
+        }
+
+        public void setFoaf(Map<String, String> foaf) {
+            this.foaf = foaf;
+        }
+
+        public String getLogin() {
+            return login;
+        }
+
+        public String getUri() {
+            return uri;
+        }
+
+        public String[] getRoles() {
+            return roles;
+        }
+
+        public Map<String, String> getFoaf() {
+            return foaf;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/69cbd57a/platform/marmotta-user/src/main/resources/kiwi-module.properties
----------------------------------------------------------------------
diff --git a/platform/marmotta-user/src/main/resources/kiwi-module.properties b/platform/marmotta-user/src/main/resources/kiwi-module.properties
index c8841d3..ab0a784 100644
--- a/platform/marmotta-user/src/main/resources/kiwi-module.properties
+++ b/platform/marmotta-user/src/main/resources/kiwi-module.properties
@@ -22,12 +22,10 @@ subtitle = Profile and Account Management
 
 icon_small = /admin/img/user_small.png
 
-webservices=at.newmedialab.lmf.user.webservices.UserWebService,\
-            at.newmedialab.lmf.user.webservices.UserManagementWebService
+webservices=org.apache.marmotta.platform.user.webservices.UserWebService,\
+            org.apache.marmotta.platform.user.webservices.UserManagementWebService
 
 
-entities=at.newmedialab.lmf.user.model.UserAccount
-
 adminpages=/me.html,\
     /admin/users.html
 

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/69cbd57a/platform/marmotta-versioning/src/main/java/at/newmedialab/lmf/versioning/api/MementoService.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-versioning/src/main/java/at/newmedialab/lmf/versioning/api/MementoService.java b/platform/marmotta-versioning/src/main/java/at/newmedialab/lmf/versioning/api/MementoService.java
deleted file mode 100644
index 1724518..0000000
--- a/platform/marmotta-versioning/src/main/java/at/newmedialab/lmf/versioning/api/MementoService.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * Copyright (C) 2013 Salzburg Research.
- *
- * 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 at.newmedialab.lmf.versioning.api;
-
-import at.newmedialab.lmf.versioning.exception.MementoException;
-import at.newmedialab.lmf.versioning.model.MementoVersionSet;
-import org.apache.marmotta.kiwi.versioning.model.Version;
-import org.openrdf.model.Resource;
-import java.util.Date;
-
-/**
- * ...
- * <p/>
- * Author: Thomas Kurz (tkurz@apache.org)
- */
-public interface MementoService {
-
-    //public Version getNextVersion(Resource resource, Version version) throws MementoException;
-
-    //public Version getPreviousVersion(Resource resource, Version version) throws MementoException;
-
-    /**
-     * returns the version for a resource that was current on the given date
-     * @param resource a uri resource
-     * @param date a date
-     * @return the version with respect to the date
-     * @throws MementoException
-     */
-    public Version getVersion(Resource resource, Date date) throws MementoException;
-
-    //public Version getLastVersion(Resource resource) throws MementoException;
-    //public Version getFirstVersion(Resource resource) throws MementoException;
-
-    /**
-     * returns a memento version set that includes first, last, current, prev and next version with respect
-     * to a given date and resource
-     * @param resource a requested resource
-     * @param date a requested date
-     * @return a memento version set
-     * @throws MementoException
-     * @see MementoVersionSet
-     */
-    public MementoVersionSet getVersionSet(Resource resource, Date date) throws MementoException;
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/69cbd57a/platform/marmotta-versioning/src/main/java/at/newmedialab/lmf/versioning/api/VersionSerializerService.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-versioning/src/main/java/at/newmedialab/lmf/versioning/api/VersionSerializerService.java b/platform/marmotta-versioning/src/main/java/at/newmedialab/lmf/versioning/api/VersionSerializerService.java
deleted file mode 100644
index a16446a..0000000
--- a/platform/marmotta-versioning/src/main/java/at/newmedialab/lmf/versioning/api/VersionSerializerService.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * Copyright (C) 2013 Salzburg Research.
- *
- * 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 at.newmedialab.lmf.versioning.api;
-
-import at.newmedialab.lmf.versioning.io.VersionSerializer;
-import org.apache.marmotta.commons.http.ContentType;
-
-import java.io.IOException;
-import java.util.List;
-
-/**
- * Manages serialisation writers for Version objects
- * <p/>
- * Author: Thomas Kurz (tkurz@apache.org)
- */
-public interface VersionSerializerService {
-
-    /**
-     * returns a serializer for Version objects on a given ContentType
-     * @param type a list of mimetype (from Accept header)
-     * @return a serializer
-     */
-    public VersionSerializer getSerializer(List<ContentType> type) throws IOException;
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/69cbd57a/platform/marmotta-versioning/src/main/java/at/newmedialab/lmf/versioning/exception/MementoException.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-versioning/src/main/java/at/newmedialab/lmf/versioning/exception/MementoException.java b/platform/marmotta-versioning/src/main/java/at/newmedialab/lmf/versioning/exception/MementoException.java
deleted file mode 100644
index b0307e5..0000000
--- a/platform/marmotta-versioning/src/main/java/at/newmedialab/lmf/versioning/exception/MementoException.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * Copyright (C) 2013 Salzburg Research.
- *
- * 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 at.newmedialab.lmf.versioning.exception;
-
-/**
- * Exception is thrown if something went wrong in memento versioning
- * <p/>
- * Author: Thomas Kurz (tkurz@apache.org)
- */
-public class MementoException extends Exception {
-
-    public MementoException() {}
-
-    public MementoException(String m) {
-        super(m);
-    }
-
-    public MementoException(Throwable t) {
-        super(t);
-    }
-
-}