-1

Is it possible to provide a user with an ability to login using either his ordinary username or it's alternative?

The reason I need the feature is following. We use emails as usernames (customer's requirement), which are both valid as user@mail.domain.com and user@domain.com for the same user. Some of them used to utilize the first notation, others the second.

Users are being authenticated via LDAP, which is read-only for me, so I can't just add a second mail atrribute to the user record. Any ideas please?

no id
  • 1,642
  • 3
  • 24
  • 36

1 Answers1

1

The solution I ended up with is based on this answer: https://stackoverflow.com/a/1422202/711031. I use the following FilteredRequest implementation:

public class LoginDomainCutFilter implements Filter {        
    public void init(FilterConfig arg0) throws ServletException {
    }

    public void destroy() {        
    }

    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        chain.doFilter(new FilteredRequest(request), response);
    }

    private static class FilteredRequest extends HttpServletRequestWrapper {
        public FilteredRequest(ServletRequest request) {
            super((HttpServletRequest) request);
        }

        public String getParameter(String paramName) {
            String value = super.getParameter(paramName);
            if ("j_username".equals(paramName)) {
                value = cutSuffix(value, "@mail.domain.com");
                value = cutSuffix(value, "@domain.com");
            }
            return value;
        }

        private String cutSuffix(String value, String suffix) {
            if (value.endsWith(suffix)) value = value.substring(0, value.length() - suffix.length());
            return value;
        }
    }
}

In this case we should register our filter at web.xml before the Spring Security filter:

<filter>
    <filter-name>loginDomainCutFilter</filter-name>
    <filter-class>org.mydomain.myapp.LoginDomainCutFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>loginDomainCutFilter</filter-name>
    <url-pattern>/j_spring_security_check</url-pattern>
</filter-mapping>

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Finishing touch is to change (mail={0}) to (mail={0}@*) in your LDAP search filter:

<beans:bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
    <beans:constructor-arg index="0" value="ou=users,ou=myorgunit"/>      
    <beans:constructor-arg index="1" value="(mail={0}@*)"/>
    <beans:constructor-arg index="2" ref="contextSource"/>
    <beans:property name="searchSubtree" value="true"/>
</beans:bean>

Please note that side-effect of the solution is that Spring Security username will no longer contain @domain suffix, so you should add it manually when you need to display the email. You should decide which one is primary, however.

You should also note that the filter doesn't affect usernames that contain another domain suffix, or doesn't have suffix at all. This is done for purpose, and you can add a simple check for that.

Now user could login as user@mail.domain.com, user@domain.com or even user. If you don't like the latter "bonus behaviour", you can also add a check.

Community
  • 1
  • 1
no id
  • 1,642
  • 3
  • 24
  • 36