Wednesday, November 12, 2014

Java 8 : Not a Paradigm Shift. Just Revisiting the Old Roots 2

This post is a continuation of previous post.

Recently I was privileged enough to see two great talks by two Industry Experts. Namely Jessica Kerr and Dr. Venkat Subramaniam and I have the links to those talks at references section and I strongly advise to watch those. First I watched Jessica Kerr's talk on Functional Principles for Object-Oriented Developers and secondly I watched Dr. Subramaniam's talk on Java 8 Language Capabilities. What's in It for You?. I am really glad that I watched those videos in that order because it made me understand the problems prior to Java 8 and how Java 8 has solved those problems elegantly.

Main takeouts from Jessica's talk are the followings;
  1. Function/Methods should not modify shared mutable states.
  2. Function/Methods should not modify input parameters.
  3. Function/Methods should not do harm to the world.
  4. Function/Methods should not change the execution flow (Exceptions must be returned as data not thrown).
She clearly goes through the benefits of being functional and how it can be achieved in different languages including Java prior to Java 8 using Google Guava library. She further explains that our code must move away from being Imperative to being more Functional/Declarative. In the sense we must say what we are need to do but not how to do it. One great example she points out is SQL. SQL language is highly declarative where we don't care how Oracle, MySQL, MS SQL RDBMS's store data underneath. We just say I want all the data of customers by just issuing "SELECT * FROM Customers". This is a really strong concept because this gives the actual Oracle, MySQL, MS SQL implementations to change transparently without ever breaking the client code. Those RDBMS's can retrieve data sequentially, parallel or in any other form. More on this through the words of Jessica herself;

"The power of SQL's declarative style isn't about swapping out Oracle for MySQL; any standard can do that. It's more about, for a given query, the database is free to swap out its strategy based on the shape of the data.
Say you want to count customers in the UK with open orders. (approximate syntax, crude table design)

SELECT COUNT(DISTINCT customer_id) FROM customers JOIN orders ON customer_id
WHERE orders.status = 'OPEN'
AND customer.country = 'UK'

If both tables are small, the database might start with the join and then filter.
If the order table is huge but very few of them are OPEN, the database might start by finding open orders, then connect them to customers, then filter again.
If the customers table is partitioned, the database might split up the table and run in parallel on each partition.

This is the power of a declarative style, of telling the database WHAT to do, not HOW to go about it. All within one underlying database implementation!"

Dr. Subramaniam's talk further verifies the claims of Jessica and explains in detail how Java 8 allows Developers to make the transition from being Imperative to being more Functional/Declarative by introducing Lambda Expressions and Streams. Lambda Expressions makes functions act also as first class citizens allowing Functional/Declarative style coding. One code excerpt I took from Dr. Subramaniam's talk is the following;

import java.util.List;
import java.util.Arrays;
import java.util.function.Consumer;

public class Sample {

    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        //Imperative
        //External Iteration

        for(int i = 0;i<numbers.size();i++) {
            System.out.println(numbers.get(i));
        }

        for(int e:numbers) {
            System.out.println(e);
        }

        //Internal Iteration

        numbers.forEach(new Consumer<Integer>() {
            public void accept(Integer no) {
                System.out.println(no);
            }
        });

        numbers.forEach((Integer no) -> System.out.println(no));

        numbers.forEach((no) -> System.out.println(no));

        numbers.forEach(no -> System.out.println(no));

        numbers.forEach(System.out::println);

        //Functional/Declarative
    }
}

The above code can be described as the blue print of Imperative to Functional/Declarative evolution in Java. The code begins being highly Imperative where we need to tell how to loop a Collection of numbers then it gradually evolves to become a highly Functional/Declarative where Iteration and Logic is handed over to the Collection itself. All the codes print out the same results.

Furthermore he shows how mutations takes place with Imperative code and how we can eliminate mutations by making use of Functional/Declarative style of coding in Java 8. Following code describes;

import java.util.List;
import java.util.Arrays;
import java.util.function.*;

public class Sample1 {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        // Imperative
        int total = 0;
        for(int e:numbers) {
            total += e;
        }    
        System.out.println(total);

        // Functional/Declarative
        System.out.println(numbers.stream()
                                  .reduce(0, (c, e) -> { return c + e; }));

        // Imperative
        total = 0;
        for(int e:numbers) {
            if(e % 2 == 0) {
                total += e;
            }
        }     
        System.out.println(total);

        // Functional/Declarative
                System.out.println(numbers.stream()
                                          .filter(e -> e % 2 == 0)
                                          .reduce(0, (c, e) -> { return c + e; }));
        
        // Imperative
        total = 0;
        for(int e:numbers) {
              total += (e * 2);
        }     
        System.out.println(total);

        // Functional/Declarative
                System.out.println(numbers.stream()
                                          .map(e -> e * 2)
                                          .reduce(0, (c, e) -> { return c + e; }));

        // Imperative
        int no = 0;
        for(int e:numbers) {
             if(e > 3 && e % 2 == 0) {
                 no = e;
                 break;
             }  
        }     
        System.out.println(no);

        // Functional/Declarative
        System.out.println(numbers.stream()
                                  .filter(e -> e > 3)
                                  .filter(e -> e % 2 == 0)
                                  .findFirst()
                                  .orElse(0));

        // Imperative
        System.out.println(total(numbers, e -> true));
        System.out.println(total(numbers, e -> e % 2 == 0));
        System.out.println(total(numbers, e -> e % 2 == 1));

        // Functional/Declarative
        System.out.println(total2(numbers, e -> true));
        System.out.println(total2(numbers, e -> e % 2 == 0));
        System.out.println(total2(numbers, e -> e % 2 == 1));

    }

    public static int total(List<Integer> numbers, Predicate<Integer> condition) {
        int total = 0;
        for(int e:numbers) {
            if(condition.test(e)) {
                total += e;
            }
        }
        return total;
    }

    public static int total2(List<Integer> numbers, Predicate<Integer> condition) {
        return numbers.stream()
                      .filter(condition)
                      .reduce(0, (c, e) -> c + e);
    }
    
}

The fact of the matter is Imperative code with mutations can cause headaches and hair loss if they need parallelism. Where as the Functional/Declarative style of coding in the above code can be parallelized by just changing "numbers.stream()" to "numbers.parallelStream()". That's it.

This is because in Functional/Declarative we are saying what needs to be done not how to do it. So how to do it can be decided by the JVM just as how RDBMS decide how to retrieve data for a particular SQL query. Furthermore Functional/Declarative style is combined with Lazy (Efficient) execution where there are Intermediate (map, filter) and Terminal (reduces, findFirst) functions. The Stream will not be evaluated until we call a Terminal function making our code efficient.

Both of the speaker agree on one thing. Familiar code is not necessarily Readable code. Just because we have written for loops to iterate a zillion times doesn't mean it is not complex. Don't be fooled by thinking that because Java 8 Functional/Declarative style of coding is Complex because it looks Unfamiliar. May be it is the best and efficient way to do what you really want to do.

I would like to end this by a quote by Dr. Subramaniam, he states "The biggest change in Java 8 are in the minds of the programmers".

References
  1. Functional Principles for Object-Oriented Developers - By Jessica Kerr
  2. Java 8 Language Capabilities. What's in It for You? - By Dr. Venkat Subramaniam

Java 8 : Not a Paradigm Shift. Just Revisiting the Old Roots 1

When I started my Bachelor's in Software Engineering back in 2007 during very early stages I was attending a Module for Programming Principles and there the lecturer said that our programs must never use global variables (Module was using C++) and each problem should be broken into a Function/Method essentially the practice Functional Decomposition. But during this time I was working as a Java Developer for a Company and my inner Java Developer opposed to this.


As Java being an Object Oriented Programming language, we are advised to think in terms of Objects rather than Function/Method. Practically functions/methods are second class citizens in Java. There is no way a Function/Method can exist without it being attached to a Class or being part of an Object. So I thought Functional Decomposition is old school and was only applicable for languages that is highly function oriented like C/C++.

But couple of years back I started reading the book Java Concurrency in Practice book and it stated that thread safety is all about protecting shared mutable state. If a Class in Java has no instance or static variables that Class becomes thread safe. One theory I learned from that book is that,

"If there are shared mutable states in a Class and if more than one thread reads those states and also if at least one thread modifies those states then access (read/modification) to those states must be synchronized"

So it all came back to me, What I learnt in 2007 as part of my Bachelor's is actually part of Java also. Global variables can be considered as shared mutable states. It is better if a Class has lesser no of shared mutable states so that in can become more concurrent friendly. Because synchronization is costly, be it Monitor lock, Copy-On-Write, Compare-And-Swap, etc. all must be used to a minimum level with shared mutable variables or the program performance can degrade.

Best approach is Immutability in classes. Immutable classes are inherently thread safe and performance degrading is not a concern. For example Java String class immutable being that after instantiate and initialization its state can not be modified. Invoking almost every Method on a String object will produce a new String object.

Furthermore the theory I learned in 2007 is so much alive today. Functional Decomposition is actually the ideal solution for today's problems. Problems broken down into Functions/Methods are easier to code/test/debug/maintain.

Next we'll see how Java 8 Helps to achieve Immutability and Functional Decomposition.

References

  1. Java Concurrency in Practice - http://jcip.net/

Wednesday, October 22, 2014

Neo4j Graph Database Backend for Spring Security Acl 2

Problem

Discussed in previous post

Design

The first challenge was Modelling a set of Tables with Relationships to a Graph. After studying the Tables and Their Relationships I came up with the following Design.

This design can be improved but I stuck with this because the intention was to increase performance not to win a Design competition. Furthermore this design covers the Domain of Spring Security ACL concisely so I stuck with this. Naming of the relationships could be improved but I like these.

In order to successfully provide a Neo4j back-end for Spring Security ACL we must implement three interfaces with Neo4j specific implementation.
  1. LookupStrategy - Used to Read Acls based on Class Name and Instance Id
  2. AclService - Non Mutable Acl related Services
  3. MutableAclService - Mutable Acl related Services

Implementation Decisions

I used Spring-Data-Neo4j project which is an abstraction layer on top of the Neo4j Graph Database which allows annotated classes to be represented as Nodes and Edges, which is convenient for Rapid Development. Furthermore it allows Repositories to do CRUD operations also but in this project I opted not to use them and instead used Neo4jTemplate because I knew I would need to write alot of Dynamic Cypher queries.

Development

The full source of the development is available at https://github.com/shazin/spring-security-acl-neo4j

Testing

The biggest question is "Will it be faster than RDBMS based implementations?". If not the whole project was a failure. Test coverage was done on both Mutable and Non Mutable Acl Services. Testing Non Mutable Acl Service will cover Lookup Strategy as it is used underneath. 

Neo4j In-memory Test Database was used to Test. This is a JVM based, Production Not Ready, Single Database instance. Assuming Production ready Neo4j Embedded or Neo4j Server Databases will increase performance (It ideally should) I decided to test using this. 

The RDBMS I used to Test against was H2, which is also a JVM based, but Production Ready In-memory Database. 

Both being in-memory implementations and being JVM based somewhat testifies that the underlying Storage hardware has no input in performance (SATA, SSD, doesn't matter) and no latency due to Network congestion.

And I was using the Ubuntu 14.04 LTS 64-bit Operating system with Intel Core i7 Processor, 4 Gb RAM and Sun JDK 8.

Test Data comprised of 200 ACL Entries (2 for each Object Identity), 3 Sids (Including logged in User Sid), 100 Classes and 100 Object Identities.

Testing was mainly focused on Retrieval and for to retrieve 50 non following Object Identities with ACL Entries (2 for each Object Identity) while running four random times with an Empty Cache, following were the results. 


The results are in Nanoseconds and Neo4j based Spring Security Acl implementation is a clear winner!

Conclusion

Neo4j clearly stands up for its claims and with this implementation Spring Security ACL could also reach its fullest potential. Can clearly say that this is one of the fastest backend implementations for Spring Security ACL. Even though the difference is in Nanoseconds, the performance will matter with higher volume of Users, Object Identities, Sids and ACL Entries. 

The code base could be improved, specially in Cypher queries thus increasing performance even more. Anyone who likes to contribute is welcome.

This doesn't mean that RDBMS are now obsolete. I personally think that RDBMS will be here for at least another 20 years if not more!

And constructive criticism is always welcome.

References
  1. http://neo4j.com/docs/stable/introduction.html - Cypher Language
  2. http://www.h2database.com/html/main.html - H2 Database


Neo4j Graph Database Backend for Spring Security Acl 1

As part of work here at Mimos, I have been working a lot with Spring Security. Some of my previous posts are testament for this. I even got the chance to work with Spring Security ACL which is a project which also comes under Spring Security eco-system and covers the "Authorization" part of Security. I feel Spring Security ACL project is seriously under-rated and one factor which stops it from reaching its fullest potential is in my opinion its Data store end. 

Predominantly design to work with a Relational Database, Spring Security ACL Team have done a great job to reduce the round trips to fetch data from Database by using Caching extensively which decreases data read time heavily.  Yet in a production system where ACL data also tend to change rapidly and with higher volume of users, ACLs and Objects to Protect, Bottleneck at Data end is inevitable. 

Furthermore Spring Security ACL Data is distributed in 4 tables named acl_sid, acl_class, acl_object_identity and acl_entry. So to query and retrieve ACL entries for a Principal or Role for a Particular class instance, Joining of these 4 tables is required. 

Also I got the exposure to do a Research and Development on Neo4j Graph Database which is a NoSQL, Schema-less, Graph Database which stores Data in the form of Property Nodes and Edges.

Neo4j is widely used in the Industry from Courier Route Decision Making to Finding a Date Match. Neo4j is said to be really good to represent Highly Connected Data because it stores all the Data in a Graph and said to be able to Model the real world as close as possible.

While reading through Neo4j Use Cases, I found that a Telecommunication company has used Neo4j for its Identity and Access Management system to improve performance. With Neo4j they have managed to reduce load time from Minutes to Milliseconds. 

This got me thinking and lit a light bulb over my head. What if I can write a Data backend for Spring Security ACL using Neo4j? Easier said than done. Neo4j being a Graph Database is a completely different paradigm with its own query language to named Cypher. 

References
  1. http://docs.spring.io/spring-security/site/docs/3.0.x/reference/domain-acls.html - Spring Security Acl
  2. http://neo4j.com/ - Neo4j
  3. http://neo4j.com/users/telenor/ - Telecom Use Case

Tuesday, September 30, 2014

Spring Security Filter Chain Registration Using WebApplicationInitializer for Servlet 3.x

Starting from Servlet 3.x Specification some code saving features have been introduced such as XML less annotation based Servlet and Filter registration. In conjunction with this Spring has introduced WebApplicationInitializer interface which allows the registration of Servlet and Filters using Java instead of using web.xml file.

This is neat feature because this will eliminate the need for the XML files required in the Spring MVC based web applications. Since most of the Spring Application Context configurations are also directing towards Java Config, Moving to would be ideal;

I read the documentation of the Spring WebApplicationInitializer and was able to register both DispatcherServlet and DelegatingFilterProxy in using it. So the following web.xml tags;

<context-param>
    <param-name>contextClass</param-name>
    <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
  </context-param>
  <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>com.lkbotics.visualizer.config.AppConfig</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <filter>
      <filter-name>springSecurityFilterChain</filter-name>
      <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
      <async-supported>true</async-supported>
  </filter>
  <filter-mapping>
      <filter-name>springSecurityFilterChain</filter-name>
      <url-pattern>/*</url-pattern>
  </filter-mapping>
  <filter>
      <filter-name>eTagFilter</filter-name>
      <filter-class>org.springframework.web.filter.ShallowEtagHeaderFilter</filter-class>
      <async-supported>true</async-supported>
  </filter>
  <filter-mapping>
      <filter-name>eTagFilter</filter-name>
      <url-pattern>/*</url-pattern>
  </filter-mapping>
  <servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextClass</param-name>
        <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </init-param>
    <init-param>
        <param-name>contextConfigLocation</param-name>
          <param-value>com.lkbotics.visualizer.web.config.MvcConfig</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    <async-supported>true</async-supported>
  </servlet>
  <servlet-mapping>
    <servlet-name>appServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

Can effectively be replaced by the following implementation of WebApplicationInitializer

import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.filter.ShallowEtagHeaderFilter;
import org.springframework.web.servlet.DispatcherServlet;

import com.lkbotics.visualizer.config.AppConfig;
import com.lkbotics.visualizer.web.config.MvcConfig;

public class CustomWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext container) throws ServletException {
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
        rootContext.register(AppConfig.class);
        
        container.addListener(new ContextLoaderListener(rootContext));
        
        AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
        dispatcherContext.register(MvcConfig.class);
        
        FilterRegistration.Dynamic springSecurityFilterChain = container.addFilter("springSecurityFilterChain", new DelegatingFilterProxy());
        springSecurityFilterChain.addMappingForUrlPatterns(null, false, "/*");
        springSecurityFilterChain.setAsyncSupported(true);
        
        FilterRegistration.Dynamic shallowETagFilter = container.addFilter("shallowETagFilter", new ShallowEtagHeaderFilter());
        shallowETagFilter.addMappingForUrlPatterns(null, true, "/*");
        shallowETagFilter.setAsyncSupported(true);
        
        ServletRegistration.Dynamic dispatcher = container.addServlet("servletDispatcher", new DispatcherServlet(dispatcherContext));
        dispatcher.setLoadOnStartup(1);
        dispatcher.setAsyncSupported(true);
        dispatcher.addMapping("/");        
    }

}

As usual Spring Security requirements apply, There must be FilterChainProxy bean registered with the name springSecurityFilterChain or custom bean name must be passed in while instantiating the DelegatingFilterProxy inside WebApplicationInitializer.

Caveats [1]

web.xml versioning

WEB-INF/web.xml and WebApplicationInitializer use are not mutually exclusive; for example, web.xml can register one servlet, and a WebApplicationInitializer can register another. An initializer can even modify registrations performed in web.xml through methods such as ServletContext#getServletRegistration(String). However, if WEB-INF/web.xml is present in the application, its version attribute must be set to "3.0" or greater, otherwise ServletContainerInitializer bootstrapping will be ignored by the servlet container.


References
  1. WebApplicationInitializer
  2. FilterRegistration.Dynamic

Wednesday, July 23, 2014

Spring Security Custom FilterChainProxy using Java Configuration

In a previous post I wrote how to custom configure FilterChainProxy using Java Bean XML configuration file. I got some feedback and of the things I was pointed out was that it could also be done using Java configuration instead of XML configuration. But at that time I couldn't do it because we were using XML configuration files for beans. But now as part of my work I needed to work with Spring using Java configuration. So I thought this is the right time to go back and write the whole custom FilterChainProxy configuration in Java configuration.

After some documentation reading, trial and error, stackoverflow I managed to get the following Java configuration to work as exactly as same as my previous post's XML configuration.


import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;

import javax.inject.Inject;
import javax.servlet.ServletException;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.intercept.RunAsManager;
import org.springframework.security.access.intercept.RunAsManagerImpl;
import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.access.vote.RoleVoter;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.authentication.dao.ReflectionSaltSource;
import org.springframework.security.authentication.dao.SaltSource;
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
import org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource;
import org.springframework.security.web.access.expression.WebExpressionVoter;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.CookieClearingLogoutHandler;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.web.filter.RequestContextFilter;

import com.lkbotics.visualizer.util.CustomUsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Inject
    UserDetailsService userService;

    @Bean
    public AuthenticationManager authenticationManager() throws Exception {
        AuthenticationManager authenticationManager = new ProviderManager(
                Arrays.asList(authenticationProvider()));
        return authenticationManager;
    }

    @Bean
    public AuthenticationProvider authenticationProvider() throws Exception {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setUserDetailsService(userService);
        authenticationProvider.setSaltSource(saltSource());
        authenticationProvider.setPasswordEncoder(passwordEncoder());
        authenticationProvider.afterPropertiesSet();
        return authenticationProvider;
    }

    @Bean
    public SaltSource saltSource() throws Exception {
        ReflectionSaltSource saltSource = new ReflectionSaltSource();
        saltSource.setUserPropertyToUse("salt");
        saltSource.afterPropertiesSet();
        return saltSource;
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new Md5PasswordEncoder();
    }

    @Bean
    public FilterChainProxy springSecurityFilterChain()
            throws ServletException, Exception {
        List<SecurityFilterChain> securityFilterChains = new ArrayList<SecurityFilterChain>();
        securityFilterChains.add(new DefaultSecurityFilterChain(
                new AntPathRequestMatcher("/login**")));
        securityFilterChains.add(new DefaultSecurityFilterChain(
                new AntPathRequestMatcher("/resources/**")));
        securityFilterChains.add(new DefaultSecurityFilterChain(
                new AntPathRequestMatcher("/**"),
                securityContextPersistenceFilter(), 
                logoutFilter(),
                usernamePasswordAuthenticationFilter(),
                exceptionTranslationFilter(),
                filterSecurityInterceptor()));
        return new FilterChainProxy(securityFilterChains);
    }

    @Bean
    public SecurityContextPersistenceFilter securityContextPersistenceFilter() {
        return new SecurityContextPersistenceFilter(
                new HttpSessionSecurityContextRepository());
    }

    @Bean
    public ExceptionTranslationFilter exceptionTranslationFilter() {
        ExceptionTranslationFilter exceptionTranslationFilter = new ExceptionTranslationFilter(
                new LoginUrlAuthenticationEntryPoint("/login"));
        AccessDeniedHandlerImpl accessDeniedHandlerImpl = new AccessDeniedHandlerImpl();
        accessDeniedHandlerImpl.setErrorPage("/exception");
        exceptionTranslationFilter
                .setAccessDeniedHandler(accessDeniedHandlerImpl);
        exceptionTranslationFilter.afterPropertiesSet();
        return exceptionTranslationFilter;
    }

    @Bean
    public UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter()
            throws Exception {
        UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter = new UsernamePasswordAuthenticationFilter();
        usernamePasswordAuthenticationFilter
                .setAuthenticationManager(authenticationManager());
        usernamePasswordAuthenticationFilter.setAllowSessionCreation(true);
        SimpleUrlAuthenticationSuccessHandler successHandler = new SimpleUrlAuthenticationSuccessHandler(
                "/");
        successHandler.setAlwaysUseDefaultTargetUrl(true);
        usernamePasswordAuthenticationFilter
                .setAuthenticationSuccessHandler(successHandler);
        usernamePasswordAuthenticationFilter
                .setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler(
                        "/login?error=true"));
        usernamePasswordAuthenticationFilter.afterPropertiesSet();

        return usernamePasswordAuthenticationFilter;

    }

    @Bean
    public FilterSecurityInterceptor filterSecurityInterceptor()
            throws Exception {
        FilterSecurityInterceptor filterSecurityInterceptor = new FilterSecurityInterceptor();
        filterSecurityInterceptor
                .setAuthenticationManager(authenticationManager());
        filterSecurityInterceptor
                .setAccessDecisionManager(accessDecisionManager());
        filterSecurityInterceptor.setRunAsManager(runAsManager());
        LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>();
        List<ConfigAttribute> configs = new ArrayList<ConfigAttribute>();
        configs.add(new org.springframework.security.access.SecurityConfig(
                "isAuthenticated()"));
        requestMap.put(new AntPathRequestMatcher("/**"), configs);
        FilterInvocationSecurityMetadataSource filterInvocationSecurityMetadataSource = new ExpressionBasedFilterInvocationSecurityMetadataSource(
                requestMap, new DefaultWebSecurityExpressionHandler());
        filterSecurityInterceptor
                .setSecurityMetadataSource(filterInvocationSecurityMetadataSource);
        filterSecurityInterceptor.afterPropertiesSet();

        return filterSecurityInterceptor;
    }

    public AffirmativeBased accessDecisionManager() throws Exception {
        List<AccessDecisionVoter> voters = new ArrayList<AccessDecisionVoter>();
        voters.add(new WebExpressionVoter());
        voters.add(new RoleVoter());
        AffirmativeBased affirmativeBased = new AffirmativeBased(voters);
        affirmativeBased.setAllowIfAllAbstainDecisions(false);
        affirmativeBased.afterPropertiesSet();

        return affirmativeBased;
    }

    @Bean
    public RunAsManager runAsManager() throws Exception {
        RunAsManagerImpl runAsManager = new RunAsManagerImpl();
        runAsManager.setKey("V_RUN_AS");
        runAsManager.afterPropertiesSet();
        return runAsManager;
    }

    @Bean
    public LogoutFilter logoutFilter() throws ServletException {
        List<LogoutHandler> handlers = new ArrayList<LogoutHandler>();
        handlers.add(new CookieClearingLogoutHandler("JSESSIONID"));
        handlers.add(new SecurityContextLogoutHandler());
        LogoutFilter logoutFilter = new LogoutFilter("/login",
                handlers.toArray(new LogoutHandler[] {}));
        logoutFilter.afterPropertiesSet();
        return logoutFilter;
    }
    
    
}

Furthermore you will need the following configuration in web.xml to support the Java configuration.

<context-param>
    <param-name>contextClass</param-name>
    <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
  </context-param>
  <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value><PACKAGE>.SecurityConfig</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <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>
  <servlet>

The same rules applies where DelegatingFilterProxy in web.xml must be named springSecurityFilterChain because our custom FilterChainProxy in SecurityConfig is named springSecurityFilterChain.

Trackbacks/Pings

  1. Spring Blog - http://spring.io/blog/2014/07/29/this-week-in-spring-spring-xd-edition-july-29th-2014

Tuesday, June 24, 2014

Simple Redis Master/Slave Replication

Redis is an in memory key value store developed to be scale-able from ground up. Redis enables this through client side sharding as well as server side master/slave replication. In this post I am going to explain a Simple 1 Master 2 Slave Server Replication Setup for Redis in a Single Host. This can be easily moved to multiple Hosts if and when the need arises with very minor changes. For this you must have downloaded redis and compiled it. If you haven't done that please follow my previous post.
The setup I am going to create looks like the above figure, where there is a Redis master listening on port 6379 and 2 Redis slaves connecting to the Master and will be listening on ports 6380 and 6381 respectively.

You need to follow the below steps to create 2 different configuration files for the slaves. 
  1. Open a Shell Terminal
  2. Navigate to redis home directory
  3. Issue "cp redis.conf redis-slave1.conf"
  4. Issue "cp redis.conf redis-slave2.conf"
  5. Open the "redis-slave1.conf" file using a Text Editor and find the line which has the port configuration and change it so that it looks like the following;  
          port 6380

     6.  And then find the line which has the slaveof configuration and change it so that it looks like the following; 

          slaveof 127.0.0.1 6379

       7.   And then find dbfilename configuration and change to "slave1-dump.rdb" as following;

          dbfilename slave1-dump.rdb

      8.  Repeat the steps 5 - 7 with "redis-slave2.conf" but this time the port must be 6381, dbfilename becomes "slave2-dump.rdb" and slaveof configuration remains the same.
       9.  Now you can start the Master followed by the 2 Slave by issuing the following commands;          

          nohup ./src/redis-server ./redis.conf > master.log 2>&1&

          nohup ./src/redis-server ./redis-slave1.conf > slave1.log 2>&1&

          nohup ./src/redis-server ./redis-slave2.conf > slave2.log 2>&1&

     10.  Now you can issue a "./src/redis-cli" and can connect to the master or any slave by providing the "./src/redis-cli -p <Slave Port>"

The recommended setup is that All writes are done to Master and All reads are performed on Slaves.
As you can see you just need to change the "127.0.0.1" host ip in your Slaves' slaveof command if you want to move this replication setup to multiple hosts.