Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Authenticating By IP Address In Spring 3.1: Smartest Way To Do That?

I've implemented LDAP authentication using Spring Security 3.1. My security.xml file for that is posted below.

I need to alter my authentication process such that if a user comes to the site from an IP Address on a "white list" ( kept in a database table ), then that user should automatically be authenticated with Spring 3.1 and then redirected away from the login screen( not my idea, I was told to so).

If the user is not from one of the white listed IP Addresses, then s/he should be forced to go through the LDAP authentication on the login page.

I'm new to Spring and Spring Security so I went to the Spring 3.1 Reference Documentation and read all of Section I. There, I read the advice that if you have any special authentication needs you should read Section II Architecture and Implementation. I did that, very slowly and took notes.

However, since I am new to all of this I'm not sure I completely understand what I need to do and what is the smartest way of going about doing it.


Update 3: I got the skeleton code to work, here are the files I ended up with


My custom AuthenticationProvider implementation for authenticating by IP Address

// Authentication Provider To Authenticate By IP Address With Allowed IPs
// Stored in a db table


package acme.com.controller.security;

//import acme.com.controller.security.CustomUserInfoHolder;

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;

import org.apache.log4j.Logger;


public class CustomIPAddressAuthenticationProvider implements AuthenticationProvider
{

    private static final Logger logger = Logger.getLogger(CustomIPAddressAuthenticationProvider.class);
    private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();


    @Override
    public Authentication authenticate(Authentication authentication)
    throws AuthenticationException {


        WebAuthenticationDetails wad = null;
        String userIPAddress         = null;
        boolean isAuthenticatedByIP  = false;

        // Get the IP address of the user tyring to use the site
        wad = (WebAuthenticationDetails) authentication.getDetails();
        userIPAddress = wad.getRemoteAddress();


        logger.debug("userIPAddress == " + userIPAddress);

        // Compare the user's IP Address with the IP address in the database
        // stored in the USERS_AUTHENTICATED_BY_IP table & joined to the
        // USERS tabe to make sure the IP Address has a current user
        //isAuthenticatedByIP =  someDataObject.hasIPAddress(userIPAddress);
        isAuthenticatedByIP = true;


        // Authenticated, the user's IP address matches one in the database
        if (isAuthenticatedByIP)
        {

            logger.debug("isAuthenticatedByIP is true, IP Addresses match");
            UserDetails user = null;


            UsernamePasswordAuthenticationToken result = null;

            result = new UsernamePasswordAuthenticationToken("John Principal",
                                                              "PlaceholderPWE"); 

            result.setDetails(authentication.getDetails());

            return result;
        }


        // Authentication didn't happen, return null to signal that the 
        // AuthenticationManager should move on to the next Authentication provider
        return null;
    }


    @Override
    public boolean supports(Class<? extends Object> authentication)
    {
        // copied it from AbstractUserDetailsAuthenticationProvider
        return(UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
    }

}

My *-security.xml file

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:s="http://www.springframework.org/schema/security"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security-3.1.xsd">

    <s:http pattern="/login*" security="none"/>
    <s:http pattern="/search*" security="none"/>
    <s:http pattern="/css/**" security="none"/>
    <s:http pattern="/js/**" security="none"/>
    <s:http pattern="/images/**" security="none"/>




    <s:http auto-config="true" use-expressions="true">
        <s:intercept-url pattern="/**" access="isAuthenticated()" />

        <s:form-login login-page="/login"
          authentication-failure-url="/loginfailed" />
        <s:logout logout-success-url="/logout" />
    </s:http>



    <s:ldap-server url = "ldap://ldap-itc.smen.acme.com:636/o=acme.com"/>


    <bean id="customIPAddressAuthenticationProvider" class="com.acme.controller.security.CustomIPAddressAuthenticationProvider" />


    <s:authentication-manager>
        <!-- Proposed: Custom Authentication Provider: Try To Authenticate BY IP Address First, IF NOT, Authenticate WiTh THE LDAP Authentication Provider -->
        <s:authentication-provider ref="customIPAddressAuthenticationProvider" />
        <s:ldap-authentication-provider user-dn-pattern="uid={0},ou=People"/>
    </s:authentication-manager>


</beans>
like image 211
Steve Avatar asked Apr 13 '12 19:04

Steve


1 Answers

Your approach seems pretty sound, you are right in thinking that Spring will try each AuthenticationProvider until it gets a successful result, so in your case you would define your IP based provider before the LDAP provider.

Depending on your setup you may not get a WebAuthenticationDetails object on your authentication.getDetails() call. If this is the case you should add Spring's RequestContextListener or RequestContextFilter to your web.xml. You will then be able to get the source IP address by using the RequestContextHolder class and calling RequestContextHolder.getRequestAttributes().

You should only need to implement an AuthenticationProvider, there is no need to implement a UserDetailsService, UserDetails or Authentication class. You should return null if you are not able to authenticate the user via his IP address. In this case Spring will try the LDAP provider. If for some reason you do not want to pass the attempt onto LDAP you should throw an AuthenticationException which will stop the process and ultimately result in a 403 error for the user.

I hope this helps :)

like image 108
Vasily Tokarov Avatar answered Oct 19 '22 03:10

Vasily Tokarov