[SYNCOPE-1015] Added the conf parameter 'authentication.attributes' to use 
alternate attrs for authentication


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/b1e52bf5
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/b1e52bf5
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/b1e52bf5

Branch: refs/heads/SYNCOPE-808
Commit: b1e52bf5bf7e789f16f6ac8859b25e06b9d712c1
Parents: 481ec8f
Author: Francesco Chicchiriccò <ilgro...@apache.org>
Authored: Wed Feb 15 12:57:12 2017 +0100
Committer: Francesco Chicchiriccò <ilgro...@apache.org>
Committed: Wed Feb 15 12:57:12 2017 +0100

----------------------------------------------------------------------
 .../main/resources/domains/MasterContent.xml    |   9 ++
 .../persistence/jpa/inner/PlainSchemaTest.java  |   2 +-
 .../test/resources/domains/MasterContent.xml    |   9 ++
 .../core/spring/security/AuthDataAccessor.java  | 144 ++++++++++---------
 .../security/SyncopeAuthenticationProvider.java |  77 ++++++----
 .../security/SyncopeUserDetailsService.java     |  37 -----
 .../src/main/resources/securityContext.xml      |   3 -
 .../apache/syncope/fit/core/UserSelfITCase.java |   4 +-
 .../configurationparameters.adoc                |   2 +
 9 files changed, 151 insertions(+), 136 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/b1e52bf5/core/persistence-jpa/src/main/resources/domains/MasterContent.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/resources/domains/MasterContent.xml 
b/core/persistence-jpa/src/main/resources/domains/MasterContent.xml
index 5b6cab9..e208c70 100644
--- a/core/persistence-jpa/src/main/resources/domains/MasterContent.xml
+++ b/core/persistence-jpa/src/main/resources/domains/MasterContent.xml
@@ -90,6 +90,15 @@ under the License.
   <CPlainAttrValue id="b5e8e79d-8039-4318-9698-fe5e181ebe98"
                    attribute_id="e5a712ad-53fd-4102-ba55-fb45caed5f7b" 
booleanValue="1"/>
 
+  <SyncopeSchema id="authentication.attributes"/>
+  <PlainSchema id="authentication.attributes" type="String" multivalue="1" 
uniqueConstraint="0" readonly="0"/>
+  <CPlainAttr id="577c6c4d-7149-43c2-9821-9ab4510effbd"
+              owner_id="cd64d66f-6fff-4008-b966-a06b1cc1436d" 
schema_id="authentication.attributes"/>
+  <CPlainAttrValue id="c13660b5-926c-47ea-946d-52db32dd492b"
+                   attribute_id="577c6c4d-7149-43c2-9821-9ab4510effbd" 
stringValue="username"/>
+  <CPlainAttrValue id="0f112dbd-00d4-441c-b732-331e7f348f8a"
+                   attribute_id="577c6c4d-7149-43c2-9821-9ab4510effbd" 
stringValue="email"/>
+
   <SyncopeSchema id="authentication.statuses"/>
   <PlainSchema id="authentication.statuses" type="String" multivalue="1" 
uniqueConstraint="0" readonly="0"/>
   <CPlainAttr id="888ae8e1-a295-4ee2-a15e-31dbf6dfc3f9"

http://git-wip-us.apache.org/repos/asf/syncope/blob/b1e52bf5/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainSchemaTest.java
----------------------------------------------------------------------
diff --git 
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainSchemaTest.java
 
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainSchemaTest.java
index 918f9fc..b20bc4b 100644
--- 
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainSchemaTest.java
+++ 
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainSchemaTest.java
@@ -47,7 +47,7 @@ public class PlainSchemaTest extends AbstractTest {
     @Test
     public void findAll() {
         List<PlainSchema> schemas = plainSchemaDAO.findAll();
-        assertEquals(39, schemas.size());
+        assertEquals(40, schemas.size());
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/syncope/blob/b1e52bf5/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml 
b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
index 28c6715..7337f4f 100644
--- a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
+++ b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
@@ -90,6 +90,15 @@ under the License.
   <CPlainAttrValue id="b5e8e79d-8039-4318-9698-fe5e181ebe98"
                    attribute_id="e5a712ad-53fd-4102-ba55-fb45caed5f7b" 
booleanValue="1"/>
 
+  <SyncopeSchema id="authentication.attributes"/>
+  <PlainSchema id="authentication.attributes" type="String" multivalue="1" 
uniqueConstraint="0" readonly="0"/>
+  <CPlainAttr id="577c6c4d-7149-43c2-9821-9ab4510effbd"
+              owner_id="cd64d66f-6fff-4008-b966-a06b1cc1436d" 
schema_id="authentication.attributes"/>
+  <CPlainAttrValue id="c13660b5-926c-47ea-946d-52db32dd492b"
+                   attribute_id="577c6c4d-7149-43c2-9821-9ab4510effbd" 
stringValue="username"/>
+  <CPlainAttrValue id="0f112dbd-00d4-441c-b732-331e7f348f8a"
+                   attribute_id="577c6c4d-7149-43c2-9821-9ab4510effbd" 
stringValue="email"/>
+
   <SyncopeSchema id="authentication.statuses"/>
   <PlainSchema id="authentication.statuses" type="String" multivalue="1" 
uniqueConstraint="0" readonly="0"/>
   <CPlainAttr id="888ae8e1-a295-4ee2-a15e-31dbf6dfc3f9"

http://git-wip-us.apache.org/repos/asf/syncope/blob/b1e52bf5/core/spring/src/main/java/org/apache/syncope/core/spring/security/AuthDataAccessor.java
----------------------------------------------------------------------
diff --git 
a/core/spring/src/main/java/org/apache/syncope/core/spring/security/AuthDataAccessor.java
 
b/core/spring/src/main/java/org/apache/syncope/core/spring/security/AuthDataAccessor.java
index 377b96e..e8a919d 100644
--- 
a/core/spring/src/main/java/org/apache/syncope/core/spring/security/AuthDataAccessor.java
+++ 
b/core/spring/src/main/java/org/apache/syncope/core/spring/security/AuthDataAccessor.java
@@ -19,10 +19,12 @@
 package org.apache.syncope.core.spring.security;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import javax.annotation.Resource;
@@ -33,10 +35,10 @@ import org.apache.commons.collections4.SetUtils;
 import org.apache.commons.collections4.Transformer;
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
-import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.AuditElements;
 import org.apache.syncope.common.lib.types.StandardEntitlement;
-import org.apache.syncope.core.provisioning.api.EntitlementsHolder;
+import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
 import org.apache.syncope.core.provisioning.api.utils.RealmUtils;
 import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
 import org.apache.syncope.core.persistence.api.dao.ConfDAO;
@@ -44,6 +46,8 @@ import org.apache.syncope.core.persistence.api.dao.DomainDAO;
 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
 import org.apache.syncope.core.persistence.api.dao.RealmDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
+import org.apache.syncope.core.persistence.api.dao.search.AttributeCond;
+import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
 import org.apache.syncope.core.persistence.api.entity.Domain;
 import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.persistence.api.entity.Role;
@@ -61,7 +65,6 @@ import org.springframework.beans.factory.annotation.Autowired;
 import 
org.springframework.security.authentication.AuthenticationServiceException;
 import org.springframework.security.authentication.DisabledException;
 import org.springframework.security.core.Authentication;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
 import org.springframework.transaction.annotation.Transactional;
 
 /**
@@ -101,6 +104,9 @@ public class AuthDataAccessor {
     protected AnyTypeDAO anyTypeDAO;
 
     @Autowired
+    protected AnySearchDAO searchDAO;
+
+    @Autowired
     protected ConnectorFactory connFactory;
 
     @Autowired
@@ -126,13 +132,32 @@ public class AuthDataAccessor {
      * @return {@code null} if no matching user was found, authentication 
result otherwise
      */
     @Transactional(noRollbackFor = DisabledException.class)
-    public Pair<String, Boolean> authenticate(final Authentication 
authentication) {
-        String key = null;
-        Boolean authenticated = null;
+    public Pair<User, Boolean> authenticate(final Authentication 
authentication) {
+        User user = null;
+
+        CPlainAttr authAttrs = confDAO.find("authentication.attributes");
+        List<String> authAttrValues = authAttrs == null
+                ? Collections.singletonList("username")
+                : authAttrs.getValuesAsStrings();
+        for (int i = 0; user == null && i < authAttrValues.size(); i++) {
+            if ("username".equals(authAttrValues.get(i))) {
+                user = userDAO.findByUsername(authentication.getName());
+            } else {
+                AttributeCond attrCond = new 
AttributeCond(AttributeCond.Type.EQ);
+                attrCond.setSchema(authAttrValues.get(i));
+                attrCond.setExpression(authentication.getName());
+                List<User> users = 
searchDAO.search(SearchCond.getLeafCond(attrCond), AnyTypeKind.USER);
+                if (users.size() == 1) {
+                    user = users.get(0);
+                } else {
+                    LOG.warn("Value {} provided for {} does not uniquely 
identifies an user",
+                            authentication.getName(), authAttrValues.get(i));
+                }
+            }
+        }
 
-        User user = userDAO.findByUsername(authentication.getName());
+        Boolean authenticated = null;
         if (user != null) {
-            key = user.getKey();
             authenticated = false;
 
             if (user.isSuspended() != null && user.isSuspended()) {
@@ -167,7 +192,7 @@ public class AuthDataAccessor {
             }
         }
 
-        return ImmutablePair.of(key, authenticated);
+        return ImmutablePair.of(user, authenticated);
     }
 
     protected boolean authenticate(final User user, final String password) {
@@ -239,79 +264,60 @@ public class AuthDataAccessor {
     }
 
     @Transactional
-    public Set<SyncopeGrantedAuthority> load(final String username) {
-        final Set<SyncopeGrantedAuthority> authorities = new HashSet<>();
-        if (anonymousUser.equals(username)) {
-            authorities.add(new 
SyncopeGrantedAuthority(StandardEntitlement.ANONYMOUS));
-        } else if (adminUser.equals(username)) {
-            CollectionUtils.collect(
-                    EntitlementsHolder.getInstance().getValues(),
-                    new Transformer<String, SyncopeGrantedAuthority>() {
-
-                @Override
-                public SyncopeGrantedAuthority transform(final String 
entitlement) {
-                    return new SyncopeGrantedAuthority(entitlement, 
SyncopeConstants.ROOT_REALM);
-                }
-            }, authorities);
+    public Set<SyncopeGrantedAuthority> getAuthorities(final User user) {
+        Set<SyncopeGrantedAuthority> authorities = new HashSet<>();
+        if (user.isMustChangePassword()) {
+            authorities.add(new 
SyncopeGrantedAuthority(StandardEntitlement.MUST_CHANGE_PASSWORD));
         } else {
-            User user = userDAO.findByUsername(username);
-            if (user == null) {
-                throw new UsernameNotFoundException("Could not find any user 
with id " + username);
-            }
-
-            if (user.isMustChangePassword()) {
-                authorities.add(new 
SyncopeGrantedAuthority(StandardEntitlement.MUST_CHANGE_PASSWORD));
-            } else {
-                final Map<String, Set<String>> entForRealms = new HashMap<>();
-
-                // Give entitlements as assigned by roles (with realms, where 
applicable) - assigned either
-                // statically and dynamically
-                for (final Role role : userDAO.findAllRoles(user)) {
-                    IterableUtils.forEach(role.getEntitlements(), new 
Closure<String>() {
-
-                        @Override
-                        public void execute(final String entitlement) {
-                            Set<String> realms = entForRealms.get(entitlement);
-                            if (realms == null) {
-                                realms = new HashSet<>();
-                                entForRealms.put(entitlement, realms);
-                            }
-
-                            CollectionUtils.collect(role.getRealms(), new 
Transformer<Realm, String>() {
+            final Map<String, Set<String>> entForRealms = new HashMap<>();
 
-                                @Override
-                                public String transform(final Realm realm) {
-                                    return realm.getFullPath();
-                                }
-                            }, realms);
-                        }
-                    });
-                }
-
-                // Give group entitlements for owned groups
-                for (Group group : groupDAO.findOwnedByUser(user.getKey())) {
-                    for (String entitlement : Arrays.asList(
-                            StandardEntitlement.GROUP_READ,
-                            StandardEntitlement.GROUP_UPDATE,
-                            StandardEntitlement.GROUP_DELETE)) {
+            // Give entitlements as assigned by roles (with realms, where 
applicable) - assigned either
+            // statically and dynamically
+            for (final Role role : userDAO.findAllRoles(user)) {
+                IterableUtils.forEach(role.getEntitlements(), new 
Closure<String>() {
 
+                    @Override
+                    public void execute(final String entitlement) {
                         Set<String> realms = entForRealms.get(entitlement);
                         if (realms == null) {
                             realms = new HashSet<>();
                             entForRealms.put(entitlement, realms);
                         }
 
-                        
realms.add(RealmUtils.getGroupOwnerRealm(group.getRealm().getFullPath(), 
group.getKey()));
+                        CollectionUtils.collect(role.getRealms(), new 
Transformer<Realm, String>() {
+
+                            @Override
+                            public String transform(final Realm realm) {
+                                return realm.getFullPath();
+                            }
+                        }, realms);
+                    }
+                });
+            }
+
+            // Give group entitlements for owned groups
+            for (Group group : groupDAO.findOwnedByUser(user.getKey())) {
+                for (String entitlement : Arrays.asList(
+                        StandardEntitlement.GROUP_READ,
+                        StandardEntitlement.GROUP_UPDATE,
+                        StandardEntitlement.GROUP_DELETE)) {
+
+                    Set<String> realms = entForRealms.get(entitlement);
+                    if (realms == null) {
+                        realms = new HashSet<>();
+                        entForRealms.put(entitlement, realms);
                     }
-                }
 
-                // Finally normalize realms for each given entitlement and 
generate authorities
-                for (Map.Entry<String, Set<String>> entry : 
entForRealms.entrySet()) {
-                    SyncopeGrantedAuthority authority = new 
SyncopeGrantedAuthority(entry.getKey());
-                    
authority.addRealms(RealmUtils.normalize(entry.getValue()));
-                    authorities.add(authority);
+                    
realms.add(RealmUtils.getGroupOwnerRealm(group.getRealm().getFullPath(), 
group.getKey()));
                 }
             }
+
+            // Finally normalize realms for each given entitlement and 
generate authorities
+            for (Map.Entry<String, Set<String>> entry : 
entForRealms.entrySet()) {
+                SyncopeGrantedAuthority authority = new 
SyncopeGrantedAuthority(entry.getKey());
+                authority.addRealms(RealmUtils.normalize(entry.getValue()));
+                authorities.add(authority);
+            }
         }
 
         return authorities;

http://git-wip-us.apache.org/repos/asf/syncope/blob/b1e52bf5/core/spring/src/main/java/org/apache/syncope/core/spring/security/SyncopeAuthenticationProvider.java
----------------------------------------------------------------------
diff --git 
a/core/spring/src/main/java/org/apache/syncope/core/spring/security/SyncopeAuthenticationProvider.java
 
b/core/spring/src/main/java/org/apache/syncope/core/spring/security/SyncopeAuthenticationProvider.java
index 369b92c..9f6a3ed 100644
--- 
a/core/spring/src/main/java/org/apache/syncope/core/spring/security/SyncopeAuthenticationProvider.java
+++ 
b/core/spring/src/main/java/org/apache/syncope/core/spring/security/SyncopeAuthenticationProvider.java
@@ -18,15 +18,22 @@
  */
 package org.apache.syncope.core.spring.security;
 
+import java.util.HashSet;
+import java.util.Set;
 import javax.annotation.Resource;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.Transformer;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.types.AuditElements;
 import org.apache.syncope.common.lib.types.AuditElements.Result;
 import org.apache.syncope.common.lib.types.CipherAlgorithm;
+import org.apache.syncope.common.lib.types.StandardEntitlement;
 import org.apache.syncope.core.spring.security.AuthContextUtils.Executable;
 import org.apache.syncope.core.persistence.api.entity.Domain;
+import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.apache.syncope.core.provisioning.api.EntitlementsHolder;
 import org.apache.syncope.core.provisioning.api.UserProvisioningManager;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -36,7 +43,6 @@ import 
org.springframework.security.authentication.AuthenticationProvider;
 import org.springframework.security.authentication.BadCredentialsException;
 import 
org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
-import org.springframework.security.core.userdetails.UserDetailsService;
 
 @Configurable
 public class SyncopeAuthenticationProvider implements AuthenticationProvider {
@@ -61,8 +67,6 @@ public class SyncopeAuthenticationProvider implements 
AuthenticationProvider {
 
     protected String anonymousKey;
 
-    protected UserDetailsService userDetailsService;
-
     protected final Encryptor encryptor = Encryptor.getInstance();
 
     /**
@@ -86,10 +90,6 @@ public class SyncopeAuthenticationProvider implements 
AuthenticationProvider {
         this.anonymousKey = anonymousKey;
     }
 
-    public void setUserDetailsService(final UserDetailsService 
syncopeUserDetailsService) {
-        this.userDetailsService = syncopeUserDetailsService;
-    }
-
     @Override
     public Authentication authenticate(final Authentication authentication) {
         String domainKey = 
SyncopeAuthenticationDetails.class.cast(authentication.getDetails()).getDomain();
@@ -98,10 +98,18 @@ public class SyncopeAuthenticationProvider implements 
AuthenticationProvider {
         }
         
SyncopeAuthenticationDetails.class.cast(authentication.getDetails()).setDomain(domainKey);
 
+        final String[] username = new String[1];
         Boolean authenticated;
+        final Set<SyncopeGrantedAuthority> authorities = new HashSet<>();
+
         if (anonymousUser.equals(authentication.getName())) {
+            username[0] = anonymousUser;
             authenticated = 
authentication.getCredentials().toString().equals(anonymousKey);
+            if (authenticated) {
+                authorities.add(new 
SyncopeGrantedAuthority(StandardEntitlement.ANONYMOUS));
+            }
         } else if (adminUser.equals(authentication.getName())) {
+            username[0] = adminUser;
             if (SyncopeConstants.MASTER_DOMAIN.equals(domainKey)) {
                 authenticated = encryptor.verify(
                         authentication.getCredentials().toString(),
@@ -123,27 +131,47 @@ public class SyncopeAuthenticationProvider implements 
AuthenticationProvider {
                     }
                 });
             }
+            if (authenticated) {
+                CollectionUtils.collect(
+                        EntitlementsHolder.getInstance().getValues(),
+                        new Transformer<String, SyncopeGrantedAuthority>() {
+
+                    @Override
+                    public SyncopeGrantedAuthority transform(final String 
entitlement) {
+                        return new SyncopeGrantedAuthority(entitlement, 
SyncopeConstants.ROOT_REALM);
+                    }
+                }, authorities);
+            }
         } else {
-            final Pair<String, Boolean> authResult =
-                    AuthContextUtils.execWithAuthContext(domainKey, new 
Executable<Pair<String, Boolean>>() {
+            final Pair<User, Boolean> authResult =
+                    AuthContextUtils.execWithAuthContext(domainKey, new 
Executable<Pair<User, Boolean>>() {
 
                         @Override
-                        public Pair<String, Boolean> exec() {
+                        public Pair<User, Boolean> exec() {
                             return dataAccessor.authenticate(authentication);
                         }
                     });
             authenticated = authResult.getValue();
-            if (authenticated != null && !authenticated) {
-                AuthContextUtils.execWithAuthContext(domainKey, new 
Executable<Void>() {
+            if (authResult.getLeft() != null && authResult.getRight() != null) 
{
+                username[0] = authResult.getLeft().getUsername();
 
-                    @Override
-                    public Void exec() {
-                        
provisioningManager.internalSuspend(authResult.getKey());
-                        return null;
-                    }
-                });
+                if (authResult.getRight()) {
+                    
authorities.addAll(dataAccessor.getAuthorities(authResult.getLeft()));
+                } else {
+                    AuthContextUtils.execWithAuthContext(domainKey, new 
Executable<Void>() {
+
+                        @Override
+                        public Void exec() {
+                            
provisioningManager.internalSuspend(authResult.getLeft().getKey());
+                            return null;
+                        }
+                    });
+                }
             }
         }
+        if (username[0] == null) {
+            username[0] = authentication.getPrincipal().toString();
+        }
 
         final boolean isAuthenticated = authenticated != null && authenticated;
         UsernamePasswordAuthenticationToken token;
@@ -154,10 +182,9 @@ public class SyncopeAuthenticationProvider implements 
AuthenticationProvider {
                 @Override
                 public UsernamePasswordAuthenticationToken exec() {
                     UsernamePasswordAuthenticationToken token = new 
UsernamePasswordAuthenticationToken(
-                            authentication.getPrincipal(),
+                            username[0],
                             null,
-                            
userDetailsService.loadUserByUsername(authentication.getPrincipal().toString()).
-                            getAuthorities());
+                            authorities);
                     token.setDetails(authentication.getDetails());
 
                     dataAccessor.audit(AuditElements.EventCategoryType.LOGIC,
@@ -174,7 +201,7 @@ public class SyncopeAuthenticationProvider implements 
AuthenticationProvider {
             });
 
             LOG.debug("User {} successfully authenticated, with entitlements 
{}",
-                    authentication.getPrincipal(), token.getAuthorities());
+                    username[0], token.getAuthorities());
         } else {
             AuthContextUtils.execWithAuthContext(domainKey, new 
Executable<Void>() {
 
@@ -188,14 +215,14 @@ public class SyncopeAuthenticationProvider implements 
AuthenticationProvider {
                             null,
                             isAuthenticated,
                             authentication,
-                            "User " + authentication.getPrincipal() + " not 
authenticated");
+                            "User " + username[0] + " not authenticated");
                     return null;
                 }
             });
 
-            LOG.debug("User {} not authenticated", 
authentication.getPrincipal());
+            LOG.debug("User {} not authenticated", username[0]);
 
-            throw new BadCredentialsException("User " + 
authentication.getPrincipal() + " not authenticated");
+            throw new BadCredentialsException("User " + username[0] + " not 
authenticated");
         }
 
         return token;

http://git-wip-us.apache.org/repos/asf/syncope/blob/b1e52bf5/core/spring/src/main/java/org/apache/syncope/core/spring/security/SyncopeUserDetailsService.java
----------------------------------------------------------------------
diff --git 
a/core/spring/src/main/java/org/apache/syncope/core/spring/security/SyncopeUserDetailsService.java
 
b/core/spring/src/main/java/org/apache/syncope/core/spring/security/SyncopeUserDetailsService.java
deleted file mode 100644
index 544fc99..0000000
--- 
a/core/spring/src/main/java/org/apache/syncope/core/spring/security/SyncopeUserDetailsService.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.syncope.core.spring.security;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Configurable;
-import org.springframework.security.core.userdetails.User;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UserDetailsService;
-
-@Configurable
-public class SyncopeUserDetailsService implements UserDetailsService {
-
-    @Autowired
-    protected AuthDataAccessor dataAccessor;
-
-    @Override
-    public UserDetails loadUserByUsername(final String username) {
-        return new User(username, "<PASSWORD_PLACEHOLDER>", 
dataAccessor.load(username));
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/b1e52bf5/core/spring/src/main/resources/securityContext.xml
----------------------------------------------------------------------
diff --git a/core/spring/src/main/resources/securityContext.xml 
b/core/spring/src/main/resources/securityContext.xml
index 83b3468..3aa6079 100644
--- a/core/spring/src/main/resources/securityContext.xml
+++ b/core/spring/src/main/resources/securityContext.xml
@@ -86,14 +86,11 @@ under the License.
 
   <bean class="org.apache.syncope.core.spring.security.AuthDataAccessor"/>
 
-  <bean id="syncopeUserDetailsService" 
class="org.apache.syncope.core.spring.security.SyncopeUserDetailsService"/>
-
   <bean id="syncopeAuthenticationProvider"
         
class="org.apache.syncope.core.spring.security.SyncopeAuthenticationProvider">
     <property name="adminPassword" value="${adminPassword}"/>
     <property name="adminPasswordAlgorithm" value="${adminPasswordAlgorithm}"/>
     <property name="anonymousKey" value="${anonymousKey}"/>
-    <property name="userDetailsService" ref="syncopeUserDetailsService"/>
   </bean>
 
   <security:authentication-manager>

http://git-wip-us.apache.org/repos/asf/syncope/blob/b1e52bf5/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java
----------------------------------------------------------------------
diff --git 
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java
 
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java
index b0225d8..fef308f 100644
--- 
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java
+++ 
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java
@@ -28,7 +28,6 @@ import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import java.security.AccessControlException;
 import java.util.Map;
 import java.util.Set;
 import javax.sql.DataSource;
@@ -151,6 +150,9 @@ public class UserSelfITCase extends AbstractITCase {
 
         Pair<Map<String, Set<String>>, UserTO> self = 
clientFactory.create("rossini", ADMIN_PWD).self();
         assertEquals("rossini", self.getValue().getUsername());
+
+        Pair<Map<String, Set<String>>, UserTO> byEmail = 
clientFactory.create("ve...@syncope.org", ADMIN_PWD).self();
+        assertEquals("verdi", byEmail.getValue().getUsername());
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/syncope/blob/b1e52bf5/src/main/asciidoc/reference-guide/workingwithapachesyncope/systemadministration/configurationparameters.adoc
----------------------------------------------------------------------
diff --git 
a/src/main/asciidoc/reference-guide/workingwithapachesyncope/systemadministration/configurationparameters.adoc
 
b/src/main/asciidoc/reference-guide/workingwithapachesyncope/systemadministration/configurationparameters.adoc
index e28f4bc..b052ab8 100644
--- 
a/src/main/asciidoc/reference-guide/workingwithapachesyncope/systemadministration/configurationparameters.adoc
+++ 
b/src/main/asciidoc/reference-guide/workingwithapachesyncope/systemadministration/configurationparameters.adoc
@@ -40,6 +40,8 @@ processes, including <<password-reset,password reset>>;
 * `passwordReset.allowed` - whether the <<password-reset,password reset>> 
feature (typically via the enduser
 application) is allowed;
 * `passwordReset.securityQuestion` - whether the <<password-reset,password 
reset>> feature involves security questions;
+* `authentication.attributes` - the list of attributes whose values can be 
passed as login name for authentication;
+defaults to `username`
 * `authentication.statuses` - the list of <<workflow,workflow>> statuses for 
which users are allowed to authenticate;
 [WARNING]
 Suspended Users are anyway not allowed to authenticate.

Reply via email to