Using Spring MVC + Security I have a business requirement that the users from SEC (Security team) has full access to the application and FRAUD (Anti-fraud team) has only access to the pages that URL not contains the words "block" or "update" with case insensitive.
Bellow, all spring dependencies:
$ mvn dependency:tree | grep spring
[INFO] +- org.springframework:spring-webmvc:jar:3.1.2.RELEASE:compile
[INFO] | +- org.springframework:spring-asm:jar:3.1.2.RELEASE:compile
[INFO] | +- org.springframework:spring-beans:jar:3.1.2.RELEASE:compile
[INFO] | +- org.springframework:spring-context:jar:3.1.2.RELEASE:compile
[INFO] | +- org.springframework:spring-context-support:jar:3.1.2.RELEASE:compile
[INFO] | \- org.springframework:spring-expression:jar:3.1.2.RELEASE:compile
[INFO] +- org.springframework:spring-core:jar:3.1.2.RELEASE:compile
[INFO] +- org.springframework:spring-web:jar:3.1.2.RELEASE:compile
[INFO] +- org.springframework.security:spring-security-core:jar:3.1.2.RELEASE:compile
[INFO] | \- org.springframework:spring-aop:jar:3.0.7.RELEASE:compile
[INFO] +- org.springframework.security:spring-security-web:jar:3.1.2.RELEASE:compile
[INFO] | +- org.springframework:spring-jdbc:jar:3.0.7.RELEASE:compile
[INFO] | \- org.springframework:spring-tx:jar:3.0.7.RELEASE:compile
[INFO] +- org.springframework.security:spring-security-config:jar:3.1.2.RELEASE:compile
[INFO] +- org.springframework.security:spring-security-acl:jar:3.1.2.RELEASE:compile
Bellow, some examples of mapped URL path from spring log:
Mapped URL path [/index] onto handler 'homeController'
Mapped URL path [/index.*] onto handler 'homeController'
Mapped URL path [/index/] onto handler 'homeController'
Mapped URL path [/cellphone/block] onto handler 'cellphoneController'
Mapped URL path [/cellphone/block.*] onto handler 'cellphoneController'
Mapped URL path [/cellphone/block/] onto handler 'cellphoneController'
Mapped URL path [/cellphone/confirmBlock] onto handler 'cellphoneController'
Mapped URL path [/cellphone/confirmBlock.*] onto handler 'cellphoneController'
Mapped URL path [/cellphone/confirmBlock/] onto handler 'cellphoneController'
Mapped URL path [/user/update] onto handler 'userController'
Mapped URL path [/user/update.*] onto handler 'userController'
Mapped URL path [/user/update/] onto handler 'userController'
Mapped URL path [/user/index] onto handler 'userController'
Mapped URL path [/user/index.*] onto handler 'userController'
Mapped URL path [/user/index/] onto handler 'userController'
Mapped URL path [/search] onto handler 'searchController'
Mapped URL path [/search.*] onto handler 'searchController'
Mapped URL path [/search/] onto handler 'searchController'
Mapped URL path [/doSearch] onto handler 'searchController'
Mapped URL path [/doSearch.*] onto handler 'searchController'
Mapped URL path [/doSearch/] onto handler 'searchController'
Bellow, a test of the regular expressions used in spring-security.xml (I'm not a regex speciality, improvements are welcome =]):
import java.util.Arrays;
import java.util.List;
public class RegexTest {
public static void main(String[] args) {
List<String> pathSamples = Arrays.asList(
"/index",
"/index.*",
"/index/",
"/cellphone/block",
"/cellphone/block.*",
"/cellphone/block/",
"/cellphone/confirmBlock",
"/cellphone/confirmBlock.*",
"/cellphone/confirmBlock/",
"/user/update",
"/user/update.*",
"/user/update/",
"/user/index",
"/user/index.*",
"/user/index/",
"/search",
"/search.*",
"/search/",
"/doSearch",
"/doSearch.*",
"/doSearch/");
for (String pathSample : pathSamples) {
System.out.println("Path sample: " + pathSample
+ " - SEC: " + pathSample.matches("^.*$")
+ " | FRAUD: " + pathSample.matches("^(?!.*(?i)(block|update)).*$"));
}
}
}
Bellow, the console result of Java class above:
Path sample: /index - SEC: true | FRAUD: true
Path sample: /index.* - SEC: true | FRAUD: true
Path sample: /index/ - SEC: true | FRAUD: true
Path sample: /cellphone/block - SEC: true | FRAUD: false
Path sample: /cellphone/block.* - SEC: true | FRAUD: false
Path sample: /cellphone/block/ - SEC: true | FRAUD: false
Path sample: /cellphone/confirmBlock - SEC: true | FRAUD: false
Path sample: /cellphone/confirmBlock.* - SEC: true | FRAUD: false
Path sample: /cellphone/confirmBlock/ - SEC: true | FRAUD: false
Path sample: /user/update - SEC: true | FRAUD: false
Path sample: /user/update.* - SEC: true | FRAUD: false
Path sample: /user/update/ - SEC: true | FRAUD: false
Path sample: /user/index - SEC: true | FRAUD: true
Path sample: /user/index.* - SEC: true | FRAUD: true
Path sample: /user/index/ - SEC: true | FRAUD: true
Path sample: /search - SEC: true | FRAUD: true
Path sample: /search.* - SEC: true | FRAUD: true
Path sample: /search/ - SEC: true | FRAUD: true
Path sample: /doSearch - SEC: true | FRAUD: true
Path sample: /doSearch.* - SEC: true | FRAUD: true
Path sample: /doSearch/ - SEC: true | FRAUD: true
Tests
Scenario 1
Bellow, the important part of spring-security.xml:
<security:http entry-point-ref="entryPoint" request-matcher="regex">
<security:intercept-url pattern="^.*$" access="ROLE_SEC" />
<security:intercept-url pattern="^(?!.*(?i)(block|update)).*$" access="ROLE_FRAUD" />
<security:access-denied-handler error-page="/access-denied.html" />
<security:form-login always-use-default-target="false"
login-processing-url="/doLogin.html"
authentication-failure-handler-ref="authFailHandler"
authentication-success-handler-ref="authSuccessHandler" />
<security:logout logout-url="/logout.html"
success-handler-ref="logoutSuccessHandler" />
</security:http>
Behaviour:
FRAUD group **can't" access any page
SEC group works fine
Scenario 2
NOTE that I only changed the order of intercept-url in spring-security.xml bellow:
<security:http entry-point-ref="entryPoint" request-matcher="regex">
<security:intercept-url pattern="^(?!.*(?i)(block|update)).*$" access="ROLE_FRAUD" />
<security:intercept-url pattern="^.*$" access="ROLE_SEC" />
<security:access-denied-handler error-page="/access-denied.html" />
<security:form-login always-use-default-target="false"
login-processing-url="/doLogin.html"
authentication-failure-handler-ref="authFailHandler"
authentication-success-handler-ref="authSuccessHandler" />
<security:logout logout-url="/logout.html"
success-handler-ref="logoutSuccessHandler" />
</security:http>
Behaviour:
SEC group **can't" access any page
FRAUD group works fine
Conclusion
I did something wrong or spring-security have a bug.
The problem already was solved in a very bad way, but I need to fix it quickly. Anyone knows some tricks to debug better it without open the frameworks code?
Cheers,
Felipe