spring3 security example

This commit is contained in:
sxyx2008
2014-07-04 16:31:04 +08:00
parent db3317e5a8
commit 78beef294e
25 changed files with 1078 additions and 3 deletions
+1
View File
@@ -5,6 +5,7 @@ target
.idea
*.db
.lock
.log
*.iml
*.springBeans
.gradle
+4 -3
View File
@@ -70,6 +70,7 @@
<module>flyway-example</module>
<module>workflow-activiti-example</module>
<module>spring4-hibernate4-example</module>
<module>spring3-security-example</module>
</modules>
<properties>
@@ -345,7 +346,7 @@
<version>2.14.1</version>
</plugin>
<!-- 项目源代码分析报告 -->
<!-- 项目源代码分析报�? -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
@@ -384,7 +385,7 @@
<version>2.3</version>
</plugin>
<!-- 用于在站点中生成测试覆盖率报告 -->
<!-- 用于在站点中生成测试覆盖率报�? -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
@@ -404,7 +405,7 @@
<downloadSources>true</downloadSources>
<downloadJavadocs>false</downloadJavadocs>
<wtpversion>2.0</wtpversion>
<!-- 增加设置项目encoding的文件 -->
<!-- 增加设置项目encoding的文�? -->
<additionalConfig>
<file>
<name>.settings/org.eclipse.core.resources.prefs</name>
+70
View File
@@ -0,0 +1,70 @@
spring3-security-example
=========================
This is an example of a basic Spring 3.2.x MVC application protected by Spring Security.
To run the app locally, run *mvn tomcat7:run*.
In your browser, go to http://127.0.0.1:9090
By default there are four users:
* user / password
* admin / password
* user-disabled / password
* admin-disabled / password
All passwords are simply *password*. The 3rd and 4th user are, of course, disabled within
the database *active* boolean value, and will not be able to login.
While Spring Security makes it relatively easy (once the basic filter mechanism is understood), to
add basic web security to an application, it is not exactly straightforward when deviating from the
default database based schema for users and roles.
The SQL files to create and insert data are located under */src/main/resources/spring/db*.
This application uses an embedded HSQL database with the following schema:
***Users table***
* id (UUID)
* name (Unique varchar)
* role (FK to Roles(id))
* password (varchar)
* active (boolean)
***Roles table***
* id (UUID)
* name (Unique varchar)
--------------------------------
The Spring Security configuration is located under */src/main/resources/spring/spring-security.xml*.
The basic idea is as follows:
1. An *HsqlAuthenticationProvider* bean is defined which overrides the framework class *AbstractUserDetailsAuthenticationProvider*.
This class is responsible for checking the credentials passed by Spring Security's
default login page. The provider has a Spring data source injected for database access.
2. Various abstract methods overridden to perform the authentication. The class checks to ensure that the user is in the database,
that the password matches, and the user is active. The provider uses the data source to join on the user name and role table to pull
the user and its role from the database. Using Spring's *JdbcTemplate.queryForObject()*, an exception is thrown automatically if a single
row is not returned.
3. If the user is valid, the method returns a Spring Security *UsernamePasswordAuthenticationToken*. If not, an exception is thrown.
4. Spring takes care of the rest - if successful, the token is added to the session which enables the application to obtain the user
and its roles anytime from Spring Security. If not, Spring Security will take the error message and display an error back on the auto
generated login page.
5. Once the user is logged in, she will be redirected to the main index.htm page. Within the spring-security.xml configuration, this page is
defined to require either roles *USER* or *ADMIN* (based on the */*** expression) joined with *hasAnyRole('USER, ADMIN')*.
6. The *index.htm* page has a link to *admin.htm*. Only users with *ADMIN* role are able to access this page based on expression *hasAnyRole('ADMIN')*.
7. Note that anyone, even users that have yet to login to the app, can access files located behind the /resources URL. For example, before
logging in, go to the URL: http://127.0.0.1:9090/resources/unprotected.js
In many cases, resources (CSS, javascript, images, etc.) may need to be protected.
+138
View File
@@ -0,0 +1,138 @@
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.aimeizi</groupId>
<artifactId>maven-framework-project</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>spring3-security-example</artifactId>
<name>spring3-security-example</name>
<packaging>war</packaging>
<url>http://maven.apache.org</url>
<properties>
<spring.version>3.2.6.RELEASE</spring.version>
<spring.security.version>3.2.0.RELEASE</spring.security.version>
</properties>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.2.9</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<path>/</path>
<port>9090</port>
<!--<useTestClasspath>true</useTestClasspath>-->
<contextReloadable>true</contextReloadable>
<systemProperties></systemProperties> <!---->
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,48 @@
package org.spring3.security.example;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.util.Collection;
@Controller
public class ApplicationController {
private static final Logger log = Logger.getLogger(ApplicationController.class);
@Autowired
private UserService userService;
@RequestMapping(value = "/index.htm", method = RequestMethod.GET)
public String index(ModelMap map) {
log.debug("index.htm");
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
UserDetails userDetails =
(UserDetails) authentication.getPrincipal();
map.addAttribute("userDetails", userDetails);
Collection<? extends GrantedAuthority> roles = userService.getAuthorities(userDetails);
map.addAttribute("userDetails", userDetails);
map.addAttribute("userAuthorities", roles);
return "index";
}
@RequestMapping(value = "/admin.htm", method = RequestMethod.GET)
public String admin(ModelMap map) {
log.debug("admin.htm");
UserDetails userDetails =
(UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
Collection<? extends GrantedAuthority> roles = userService.getAuthorities(userDetails);
map.addAttribute("userDetails", userDetails);
map.addAttribute("userAuthorities", roles);
return "admin";
}
}
@@ -0,0 +1,16 @@
package org.spring3.security.example;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import java.util.Collection;
@Service
public class UserService {
@PreAuthorize("hasRole('admin')")
public Collection<? extends GrantedAuthority> getAuthorities(UserDetails userDetails) {
return userDetails.getAuthorities();
}
}
@@ -0,0 +1,85 @@
package org.spring3.security.example.model;
import java.io.Serializable;
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
private String name;
private String password;
private String role;
private Boolean active;
public User(){}
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRole() {
return this.role;
}
public void setRole(String role) {
this.role = role;
}
public Boolean getActive() {
return this.active;
}
public void setActive(Boolean active) {
this.active = active;
}
@Override
public String toString() {
return "User [id=" + this.id + ", name=" + this.name + ", role=" + this.role + ", active=" + this.active + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((this.name == null) ? 0 : this.name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (this.name == null) {
if (other.name != null)
return false;
} else if (!this.name.equals(other.name))
return false;
return true;
}
}
@@ -0,0 +1,125 @@
package org.spring3.security.example.security;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.spring3.security.example.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service("hsqlAuthenticationProvider")
public class HSQLAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider{
private static final Logger log = Logger.getLogger(HSQLAuthenticationProvider.class);
protected DataSource ds;
protected NamedParameterJdbcTemplate jdbcTemplate;
@Autowired
public void setDataSource(DataSource ds){
log.trace("setDateSource()");
this.ds = ds;
this.jdbcTemplate = new NamedParameterJdbcTemplate(ds);
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
log.trace("authenticate()");
log.debug("authenticating: " + authentication);
String clearText = String.valueOf(authentication.getCredentials());
UserDetails userDetails = this.retrieveUser(authentication.getName(), (UsernamePasswordAuthenticationToken) authentication);
if (!StringUtils.equals(clearText, userDetails.getPassword())){
throw new BadCredentialsException("invalid password");
}
if (!userDetails.isEnabled()){
throw new BadCredentialsException("User not enabled");
}
return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
}
@Override
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
log.trace("additionalAuthenticationChecks()");
log.debug("isEnabled: " + userDetails.isEnabled());
if (!userDetails.isEnabled()){
throw new BadCredentialsException("User not enabled");
}
}
@Override
@Transactional(readOnly = true)
protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
log.trace("retrieveUser()");
log.debug("retrieving user: " + username);
User user;
try {
user= this.read(username);
}
catch(Exception e){
throw new UsernameNotFoundException("User " + username + " cannot be found");
}
String userName = user.getName();
String pw = user.getPassword();
String role = user.getRole();
Collection<GrantedAuthority> auths = AuthorityUtils.createAuthorityList(role);
boolean enabled = user.getActive();
UserDetails userDetails = new org.springframework.security.core.userdetails.User(userName, pw, enabled, true, true, true, auths);
log.debug("returning new userDetails: " + userDetails);
return userDetails;
}
@Transactional(readOnly = true)
protected User read(String name) {
log.trace("read()");
log.debug("reading user: " + name);
String sql = "SELECT users.id, users.name, users.active, users.password, roles.name FROM users, roles " +
" WHERE roles.id = users.role AND" +
" UPPER(users.name) = :name";
Map<String, Object> params = new HashMap<String, Object>();
params.put("name", StringUtils.upperCase(name));
User user = this.jdbcTemplate.queryForObject(sql, params, new UserRowMapper());
return user;
}
private class UserRowMapper implements RowMapper<org.spring3.security.example.model.User>{
@Override
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new org.spring3.security.example.model.User();
user.setName(StringUtils.trim(rs.getString("users.name")));
user.setId(StringUtils.trim(rs.getString("users.id")));
user.setPassword(StringUtils.trim(rs.getString("users.password")));
user.setRole(StringUtils.trim(rs.getString("roles.name")));
user.setActive(rs.getBoolean("users.active"));
log.trace(user.toString());
return user;
}
}
}
@@ -0,0 +1,227 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
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.
-->
<!-- Authors: Chris Taylor, Ceki Gulcu. -->
<!-- Version: 1.2 -->
<!-- A configuration element consists of optional renderer
elements,appender elements, categories and an optional root
element. -->
<!ELEMENT log4j:configuration (renderer*, appender*,plugin*, (category|logger)*,root?,
(categoryFactory|loggerFactory)?)>
<!-- The "threshold" attribute takes a level value below which -->
<!-- all logging statements are disabled. -->
<!-- Setting the "debug" enable the printing of internal log4j logging -->
<!-- statements. -->
<!-- By default, debug attribute is "null", meaning that we not do touch -->
<!-- internal log4j logging settings. The "null" value for the threshold -->
<!-- attribute can be misleading. The threshold field of a repository -->
<!-- cannot be set to null. The "null" value for the threshold attribute -->
<!-- simply means don't touch the threshold field, the threshold field -->
<!-- keeps its old value. -->
<!ATTLIST log4j:configuration
xmlns:log4j CDATA #FIXED "http://jakarta.apache.org/log4j/"
threshold (all|trace|debug|info|warn|error|fatal|off|null) "null"
debug (true|false|null) "null"
reset (true|false) "false"
>
<!-- renderer elements allow the user to customize the conversion of -->
<!-- message objects to String. -->
<!ELEMENT renderer EMPTY>
<!ATTLIST renderer
renderedClass CDATA #REQUIRED
renderingClass CDATA #REQUIRED
>
<!-- Appenders must have a name and a class. -->
<!-- Appenders may contain an error handler, a layout, optional parameters -->
<!-- and filters. They may also reference (or include) other appenders. -->
<!ELEMENT appender (errorHandler?, param*,
rollingPolicy?, triggeringPolicy?, connectionSource?,
layout?, filter*, appender-ref*)>
<!ATTLIST appender
name CDATA #REQUIRED
class CDATA #REQUIRED
>
<!ELEMENT layout (param*)>
<!ATTLIST layout
class CDATA #REQUIRED
>
<!ELEMENT filter (param*)>
<!ATTLIST filter
class CDATA #REQUIRED
>
<!-- ErrorHandlers can be of any class. They can admit any number of -->
<!-- parameters. -->
<!ELEMENT errorHandler (param*, root-ref?, logger-ref*, appender-ref?)>
<!ATTLIST errorHandler
class CDATA #REQUIRED
>
<!ELEMENT root-ref EMPTY>
<!ELEMENT logger-ref EMPTY>
<!ATTLIST logger-ref
ref CDATA #REQUIRED
>
<!ELEMENT param EMPTY>
<!ATTLIST param
name CDATA #REQUIRED
value CDATA #REQUIRED
>
<!-- The priority class is org.apache.log4j.Level by default -->
<!ELEMENT priority (param*)>
<!ATTLIST priority
class CDATA #IMPLIED
value CDATA #REQUIRED
>
<!-- The level class is org.apache.log4j.Level by default -->
<!ELEMENT level (param*)>
<!ATTLIST level
class CDATA #IMPLIED
value CDATA #REQUIRED
>
<!-- If no level element is specified, then the configurator MUST not -->
<!-- touch the level of the named category. -->
<!ELEMENT category (param*,(priority|level)?,appender-ref*)>
<!ATTLIST category
class CDATA #IMPLIED
name CDATA #REQUIRED
additivity (true|false) "true"
>
<!-- If no level element is specified, then the configurator MUST not -->
<!-- touch the level of the named logger. -->
<!ELEMENT logger (level?,appender-ref*)>
<!ATTLIST logger
name CDATA #REQUIRED
additivity (true|false) "true"
>
<!ELEMENT categoryFactory (param*)>
<!ATTLIST categoryFactory
class CDATA #REQUIRED>
<!ELEMENT loggerFactory (param*)>
<!ATTLIST loggerFactory
class CDATA #REQUIRED>
<!ELEMENT appender-ref EMPTY>
<!ATTLIST appender-ref
ref CDATA #REQUIRED
>
<!-- plugins must have a name and class and can have optional parameters -->
<!ELEMENT plugin (param*, connectionSource?)>
<!ATTLIST plugin
name CDATA #REQUIRED
class CDATA #REQUIRED
>
<!ELEMENT connectionSource (dataSource?, param*)>
<!ATTLIST connectionSource
class CDATA #REQUIRED
>
<!ELEMENT dataSource (param*)>
<!ATTLIST dataSource
class CDATA #REQUIRED
>
<!ELEMENT triggeringPolicy ((param|filter)*)>
<!ATTLIST triggeringPolicy
name CDATA #IMPLIED
class CDATA #REQUIRED
>
<!ELEMENT rollingPolicy (param*)>
<!ATTLIST rollingPolicy
name CDATA #IMPLIED
class CDATA #REQUIRED
>
<!-- If no priority element is specified, then the configurator MUST not -->
<!-- touch the priority of root. -->
<!-- The root category always exists and cannot be subclassed. -->
<!ELEMENT root (param*, (priority|level)?, appender-ref*)>
<!-- ==================================================================== -->
<!-- A logging event -->
<!-- ==================================================================== -->
<!ELEMENT log4j:eventSet (log4j:event*)>
<!ATTLIST log4j:eventSet
xmlns:log4j CDATA #FIXED "http://jakarta.apache.org/log4j/"
version (1.1|1.2) "1.2"
includesLocationInfo (true|false) "true"
>
<!ELEMENT log4j:event (log4j:message, log4j:NDC?, log4j:throwable?,
log4j:locationInfo?, log4j:properties?) >
<!-- The timestamp format is application dependent. -->
<!ATTLIST log4j:event
logger CDATA #REQUIRED
level CDATA #REQUIRED
thread CDATA #REQUIRED
timestamp CDATA #REQUIRED
time CDATA #IMPLIED
>
<!ELEMENT log4j:message (#PCDATA)>
<!ELEMENT log4j:NDC (#PCDATA)>
<!ELEMENT log4j:throwable (#PCDATA)>
<!ELEMENT log4j:locationInfo EMPTY>
<!ATTLIST log4j:locationInfo
class CDATA #REQUIRED
method CDATA #REQUIRED
file CDATA #REQUIRED
line CDATA #REQUIRED
>
<!ELEMENT log4j:properties (log4j:data*)>
<!ELEMENT log4j:data EMPTY>
<!ATTLIST log4j:data
name CDATA #REQUIRED
value CDATA #REQUIRED
>
@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<!--
For more configuration information and examples see the Apache Log4j website: http://logging.apache.org/log4j/
-->
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
<!-- A time/date based rolling appender -->
<appender name="FILE" class="org.apache.log4j.FileAppender">
<param name="File" value="spring-security-custom-db.log"/>
<param name="Append" value="false"/>
<param name="Threshold" value="DEBUG"/>
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority (Thread) [Category] Message\n -->
<param name="ConversionPattern" value="%d %-5p (%t) [%c] %m%n"/>
<!-- The full pattern: Date MS Priority [Category] (Thread:NDC) Message\n
<param name="ConversionPattern" value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
-->
</layout>
</appender>
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
<param name="Threshold" value="DEBUG "/>
<param name="Target" value="System.out"/>
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%d %-5p [%c{1}] (%t) %m%n"/>
</layout>
</appender>
<!-- ================ -->
<!-- Limit categories -->
<!-- ================ -->
<category name="org.spring3.security.example">
<priority value="DEBUG"/>
</category>
<category name="org.springframework.security">
<priority value="DEBUG"/>
</category>
<category name="org.springframework">
<priority value="INFO"/>
</category>
<!-- ======================= -->
<!-- Setup the Root category -->
<!-- ======================= -->
<root>
<priority value="WARN"/>
<appender-ref ref="CONSOLE"/>
<!-- <appender-ref ref="FILE"/> -->
</root>
</log4j:configuration>
@@ -0,0 +1,32 @@
welcome=Welcome from the message bundle
invalid=invalid
required=required
notFound=has not been found
duplicate=is already in use
nonNumeric=must be all numeric
duplicateFormSubmission=Duplicate form submission is not allowed
password.noMatch=The passwords do not match.
password.invalid=The password is invalid - it must be at least 8 characters
notAllowed=This field cannot be submitted
typeMismatch.date=invalid date
typeMismatch.org.joda.time.DateTime=invalid date format (please use YYYY-MM-DD)
typeMismatch.java.math.BigDecimal=invalid number
typeMismatch.birthDate=invalid date
typeMismatch=Invalid Type
negative.widget.price=price cannot be negative
required.widget.price=price is required
required.widget.cool=cool is required
required.widget.initialTime=initial time is required
beginDateAfterEndDate=the ending date must be later than the initial date
#contactModel
required.contactModel.recipientEmail=Recipient is required.
required.contactModel.message=Message is required.
required.contactModel.subject=Subject is required.
length.contactModel.message=Message must be no larger than {0} characters
parameters.oneOrOther=Cannot have both character value and numeric value - one or the other.
@@ -0,0 +1,8 @@
welcome=Willkommen
required=muss angegeben werden
notFound=wurde nicht gefunden
duplicate=ist bereits vergeben
nonNumeric=darf nur numerisch sein
duplicateFormSubmission=Wiederholtes Absenden des Formulars ist nicht erlaubt
typeMismatch.date=ungültiges Datum
typeMismatch.birthDate=ungültiges Datum
@@ -0,0 +1 @@
# This file is intentionally empty. Message look-ups will fall back to the default "messages.properties" file.
@@ -0,0 +1,12 @@
studerw.jdbc.driver=org.hsqldb.jdbcDriver
studerw.jdbc.url=jdbc\:hsqldb\:file\:./target/app-db;shutdown\=true;
studerw.jdbc.user=SA
studerw.jdbc.pw=
#HSQL Internal database
studerw.jdbc.db.createSql=classpath\:spring/db/db_create.sql
studerw.jdbc.db.dataSql=classpath\:spring/db/db_data.sql
#Should we initialize the internal DB with creation / insertion scripts [true|false]
studerw.jdbc.db.initialize=true
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:util="http://www.springframework.org/schema/util" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:c="http://www.springframework.org/schema/c" xmlns:oxm="http://www.springframework.org/schema/oxm"
xmlns:task="http://www.springframework.org/schema/task" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.2.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd">
<context:component-scan base-package="org.spring3.security.example" annotation-config="true">
<context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice" />
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
<context:property-placeholder location="classpath:spring/app.properties" />
<task:annotation-driven />
<import resource="jdbc-config.xml" />
</beans>
@@ -0,0 +1,30 @@
--SET DATABASE DEFAULT INITIAL SCHEMA PUBLIC
CREATE TABLE users (
id character varying(36) PRIMARY KEY,
name character varying(50) NOT NULL,
role character varying(36) NOT NULL,
password character varying(100) NOT NULL,
active boolean default true NOT NULL
);
CREATE TABLE roles (
id character varying(36) PRIMARY KEY,
name character varying(50) NOT NULL
);
GRANT ALL ON TABLE users TO SA;
GRANT ALL ON TABLE roles TO SA;
ALTER TABLE users
ADD CONSTRAINT role_fk FOREIGN KEY (role)
REFERENCES roles (id);
ALTER TABLE users
ADD CONSTRAINT user_name_unique UNIQUE (name);
ALTER TABLE roles
ADD CONSTRAINT role_name_unique UNIQUE (name);
@@ -0,0 +1,10 @@
INSERT INTO roles VALUES('4A7E4CB3-97C6-40E5-839E-0C3E02972DA5', 'USER');
INSERT INTO roles VALUES('35316C1F-86EB-4D82-A4D1-B262C031BF5C', 'ADMIN');
INSERT INTO users VALUES ('C61CE088-754D-4879-BF1F-6D8E9F6C8F42', 'user', '4A7E4CB3-97C6-40E5-839E-0C3E02972DA5', 'password', true);
INSERT INTO users VALUES ('C61CE088-754D-4879-BF1F-6D8E9F6C8F43', 'admin', '35316C1F-86EB-4D82-A4D1-B262C031BF5C', 'password', true);
INSERT INTO users VALUES ('C61CE088-754D-4879-BF1F-6D8E9F6C8F44', 'user-disabled', '4A7E4CB3-97C6-40E5-839E-0C3E02972DA5', 'password', false);
INSERT INTO users VALUES ('C61CE088-754D-4879-BF1F-6D8E9F6C8F45', 'admin-disabled', '35316C1F-86EB-4D82-A4D1-B262C031BF5C', 'password', false);
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<tx:annotation-driven proxy-target-class="true"/>
<!-- Un-comment to use non-persistent in-memory database -->
<jdbc:embedded-database id="dataSource">
<jdbc:script location="classpath:spring/db/db_create.sql"/>
<jdbc:script location="classpath:spring/db/db_data.sql"/>
</jdbc:embedded-database>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"/>
</beans>
@@ -0,0 +1,23 @@
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
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.2.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd">
<beans:bean id="hsqlAuthenticationProvider" class="org.spring3.security.example.security.HSQLAuthenticationProvider" />
<http auto-config="true" use-expressions="true" disable-url-rewriting="true">
<intercept-url pattern="/resources/**" access="permitAll"/>
<intercept-url pattern="/admin.htm" access="hasAnyRole('ADMIN')"/>
<intercept-url pattern="/**" access="hasAnyRole('USER, ADMIN')"/>
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider ref="hsqlAuthenticationProvider"/>
</authentication-manager>
</beans:beans>
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p" xmlns:oxm="http://www.springframework.org/schema/oxm" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
<!-- Just look for Controller -->
<context:component-scan base-package="org.spring3.security.example" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
<context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice" />
</context:component-scan>
<mvc:annotation-driven/>
<mvc:resources mapping="/resources/**" location="/resources/" order="1" />
<context:property-placeholder location="classpath:spring/app.properties" />
<!-- this is just another convenience props instance so we can shove all of them into the Widget View in one shot -->
<util:properties id="appProperties" location="classpath:spring/app.properties" />
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
p:basename="classpath:messages/messages" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" >
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/pages/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
@@ -0,0 +1,13 @@
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
</head>
<body>
<h1>Admin-Only Page</h1>
<p>Hello, ${userDetails.username}!</p>
<p>User authorities: ${userAuthorities}</p>
<a href="/index.htm">Back</a>
</body>
</html>
@@ -0,0 +1,25 @@
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<!doctype>
<html>
<head>
<title>Home</title>
</head>
<body>
<div>
<h1>All authenticated users can see this page</h1>
<sec:authorize access="isAuthenticated()">
<p>Hello, ${userDetails.username}!</p>
<p>User authorities: ${userAuthorities}</p>
<p><a href="/j_spring_security_logout">Sign Out</a></p>
</sec:authorize>
<p>
<h2>Only Admins will be able to see this page.</h2>
<a href="/admin.htm">Admin page</a>
</p>
</div>
</body>
</html>
@@ -0,0 +1,50 @@
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>Spring Security Custom Database</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext.xml classpath:spring/spring-security.xml</param-value>
</context-param>
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>tutorial.root</param-value>
</context-param>
<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>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
@@ -0,0 +1,4 @@
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%-- Redirected because we can't set the welcome page to a virtual URL. --%>
<c:redirect url="/index.htm" />
@@ -0,0 +1 @@
//this page is accessible to all users - authenticated or not.