12 Factor Application


Twelve-Factor app은 아래 특징을 가진 SaaS 앱을 만들기 위한 방법론이다.

  • 설정 자동화를 위한 절차(declarative) 를 체계화 하여 새로운 개발자가 프로젝트에 참여하는데 드는 시간과 비용을 최소화한다.
  • OS에 따라 달라지는 부분을 명확히하고, 실행 환경 사이의 이식성을 극대화 한다.
  • 최근 등장한 클라우드 플랫폼 배포에 적합하고, 서버와 시스템의 관리가 필요없게 된다.
  • 개발 환경과 운영 환경의 차이를 최소화하고 민첩성을 극대화하기 위해 지속적인 배포가 가능하다.
  • 툴, 아키텍처, 개발 방식을 크게 바꾸지 않고 확장(scale up) 할 수 있다.

Twelve-Factor 방법론은 어떤 프로그래밍 언어로 작성된 앱에도 적용할 수 있고 백엔드 서비스(데이터베이스, 큐, 메모리 캐시 등)와 다양한 조합으로 사용할 수 있다.


출처: http://12factor.net/ko/


I. 코드베이스

버전 관리되는 하나의 코드베이스와 다양한 배포

II. 종속성

명시적으로 선언되고 분리된 종속성

III. 설정

환경(environment)에 저장된 설정

IV. 백엔드 서비스

백엔드 서비스를 연결된 리소스로 취급

V. 빌드, 릴리즈, 실행

철저하게 분리된 빌드와 실행 단계

VI. 프로세스

애플리케이션을 하나 혹은 여러개의 무상태(stateless) 프로세스로 실행

VII. 포트 바인딩

포트 바인딩을 사용해서 서비스를 공개함

VIII. 동시성(Concurrency)

프로세스 모델을 사용한 확장

IX. 폐기 가능(Disposability)

빠른 시작과 그레이스풀 셧다운(graceful shutdown)을 통한 안정성 극대화

X. dev/prod 일치

development, staging, production 환경을 최대한 비슷하게 유지

XI. 로그

로그를 이벤트 스트림으로 취급

XII. Admin 프로세스

admin/maintenance 작업을 일회성 프로세스로 실행


블로그 이미지

오픈이지 제로킴

시큐어코딩 교육/컨설팅 전문가 그룹

[1일차-01] Spring Boot



A new way to create Spring Applications



1. Spring Boot을 이용한 애플리케이션 개발


Spring Boot은 Spring 프레임워크를 사용하는 프로젝트를 아주 간단하게 셋업할 수 있는 스프링 프레임웍의 서브프로젝트이다.


Spring Boot은 spring-boot-starter-web 의존성만 설정하면 기본적인 웹 개발이 가능하도록 나머지 의존라이브러리를 준비해 준다


환경설정은 @Configuration, @EnableAutoConfiguration으로 기본 설정 가능하다.



2. start.spring.io 에서 프로젝트 생성하기


   Spring Boot을 이용한 프로젝트를 온라인에서 생성할 수 있다. 


생성된 Spring Boot Application은 압축파일로 다운로드 된다. STS에서 Maven 프로젝트로 import해서 실행한다.

<주의> 만들어진 Application은 Controller가 설정되어 있지 않으므로 @RestController 를 추가해주고, @RequestMapping을 설정해 준뒤 실행한다.




[1일차-02] Getting Started with Cloud Foundry


Deploying your First Application



1. CloudFoundry 는 VMWare에서 Ruby로 만든 오픈소스 PaaS이다.  


CloudFoundry 가 개발자에게 주는 핵심가치는 편리함이다.  즉 CloudFoundry를 사용하면 다음과 같은 귀챦은 일을 하지 않아도 된다.


- 관계형 데이터베이스 설치/운영

- NoSQL 설치/운영

- MQ 설치/운영

- 웹사이드 주소가 중요하지 않은 경우 도메인 등록

- 웹서버의 가상 호스트 설정

- 웹서버와 애플리케이션 서버간의 프록시 설정

- 트래픽에 따라 WAS개수 줄이거나 늘이기

- 배포




2.  Cloud Foundry 와 Pivotal CF 개요




3.  public cloud에서 PCF 사용 따라하기



CF CLI 설치:

http://pivotal.io/platform/pcf-tutorials/getting-started-with-pivotal-cloud-foundry/install-the-cf-cli


샘플 애플리케이션 Deploy:

http://pivotal.io/platform/pcf-tutorials/getting-started-with-pivotal-cloud-foundry/deploy-the-sample-app


로그 보기:

http://pivotal.io/platform/pcf-tutorials/getting-started-with-pivotal-cloud-foundry/view-the-logs


데이터베이스 연결하기:

http://pivotal.io/platform/pcf-tutorials/getting-started-with-pivotal-cloud-foundry/connect-a-database



애플리케이션 확장(Scale) :

http://pivotal.io/platform/pcf-tutorials/getting-started-with-pivotal-cloud-foundry/scale-the-app



기타참고 자료:

How PCF Works 
https://docs.pivotal.io/pivotalcf/concepts

PCF Documentation 
https://docs.pivotal.io/pivotalcf/installing/pcf-docs.html

Installing PCF (IaaS-specific guides for installing PCF) 
https://docs.pivotal.io/pivotalcf/installing/

Learn more about the Spring Framework 
https://spring.io/guides

Explore and download more Cloud Foundry sample apps 
https://github.com/cloudfoundry-samples/


 

4.  프로젝트를 빌드하여 PWS에 업로드하기


mvn package 

> cf push <some-app-name> -p target/hello-korea-0.0.1-SNAPSHOT.jar.

업로드후 애플리케이션이 Running 상태가 되면 브라우저에서

http://hello-korea.cfapps.io/hello  로 접속하여 정상적으로 서비스가 되는지 확인한다.



[1일차-02] Building Microservices with Spring Data Rest


Spring Data Rest


1. MicroSerices

loosely coupled SOA with Bounded Context 






Spring Cloud Connector



작성중......

블로그 이미지

오픈이지 제로킴

시큐어코딩 교육/컨설팅 전문가 그룹

Hibernate를 사용법을 친절하게 설명하는 튜터리얼이 있어서 링크들을 몽땅 긁어 왔어요. 열공^^

출처:

http://www.tutorialspoint.com/hibernate/hibernate_query_language.htm

Hibernate - Query Language


Advertisements


Hibernate Query Language (HQL) is an object-oriented query language, similar to SQL, but instead of operating on tables and columns, HQL works with persistent objects and their properties. HQL queries are translated by Hibernate into conventional SQL queries which in turns perform action on database.

Although you can use SQL statements directly with Hibernate using Native SQL but I would recommend to use HQL whenever possible to avoid database portability hassles, and to take advantage of Hibernate's SQL generation and caching strategies.

Keywords like SELECT , FROM and WHERE etc. are not case sensitive but properties like table and column names are case sensitive in HQL.

FROM Clause

You will use FROM clause if you want to load a complete persistent objects into memory. Following is the simple syntax of using FROM clause:

String hql = "FROM Employee";
Query query = session.createQuery(hql);
List results = query.list();

If you need to fully qualify a class name in HQL, just specify the package and class name as follows:

String hql = "FROM com.hibernatebook.criteria.Employee";
Query query = session.createQuery(hql);
List results = query.list();

AS Clause

The AS clause can be used to assign aliases to the classes in your HQL queries, specially when you have long queries. For instance, our previous simple example would be the following:

String hql = "FROM Employee AS E";
Query query = session.createQuery(hql);
List results = query.list();

The AS keyword is optional and you can also specify the alias directly after the class name, as follows:

String hql = "FROM Employee E";
Query query = session.createQuery(hql);
List results = query.list();

SELECT Clause

The SELECT clause provides more control over the result set than the from clause. If you want to obtain few properties of objects instead of the complete object, use the SELECT clause. Following is the simple syntax of using SELECT clause to get just first_name field of the Employee object:

String hql = "SELECT E.firstName FROM Employee E";
Query query = session.createQuery(hql);
List results = query.list();

It is notable here that Employee.firstName is a property of Employee object rather than a field of the EMPLOYEE table.

WHERE Clause

If you want to narrow the specific objects that are returned from storage, you use the WHERE clause. Following is the simple syntax of using WHERE clause:

String hql = "FROM Employee E WHERE E.id = 10";
Query query = session.createQuery(hql);
List results = query.list();

ORDER BY Clause

To sort your HQL query's results, you will need to use the ORDER BY clause. You can order the results by any property on the objects in the result set either ascending (ASC) or descending (DESC). Following is the simple syntax of using ORDER BY clause:

String hql = "FROM Employee E WHERE E.id > 10 ORDER BY E.salary DESC";
Query query = session.createQuery(hql);
List results = query.list();

If you wanted to sort by more than one property, you would just add the additional properties to the end of the order by clause, separated by commas as follows:

String hql = "FROM Employee E WHERE E.id > 10 " +
             "ORDER BY E.firstName DESC, E.salary DESC ";
Query query = session.createQuery(hql);
List results = query.list();

GROUP BY Clause

This clause lets Hibernate pull information from the database and group it based on a value of an attribute and, typically, use the result to include an aggregate value. Following is the simple syntax of using GROUP BY clause:

String hql = "SELECT SUM(E.salary), E.firtName FROM Employee E " +
             "GROUP BY E.firstName";
Query query = session.createQuery(hql);
List results = query.list();

Using Named Paramters

Hibernate supports named parameters in its HQL queries. This makes writing HQL queries that accept input from the user easy and you do not have to defend against SQL injection attacks. Following is the simple syntax of using named parameters:

String hql = "FROM Employee E WHERE E.id = :employee_id";
Query query = session.createQuery(hql);
query.setParameter("employee_id",10);
List results = query.list();

UPDATE Clause

Bulk updates are new to HQL with Hibernate 3, and deletes work differently in Hibernate 3 than they did in Hibernate 2. The Query interface now contains a method called executeUpdate() for executing HQL UPDATE or DELETE statements.

The UPDATE clause can be used to update one or more properties of an one or more objects. Following is the simple syntax of using UPDATE clause:

String hql = "UPDATE Employee set salary = :salary "  + 
             "WHERE id = :employee_id";
Query query = session.createQuery(hql);
query.setParameter("salary", 1000);
query.setParameter("employee_id", 10);
int result = query.executeUpdate();
System.out.println("Rows affected: " + result);

DELETE Clause

The DELETE clause can be used to delete one or more objects. Following is the simple syntax of using DELETE clause:

String hql = "DELETE FROM Employee "  + 
             "WHERE id = :employee_id";
Query query = session.createQuery(hql);
query.setParameter("employee_id", 10);
int result = query.executeUpdate();
System.out.println("Rows affected: " + result);

INSERT Clause

HQL supports INSERT INTO clause only where records can be inserted from one object to another object. Following is the simple syntax of using INSERT INTO clause:

String hql = "INSERT INTO Employee(firstName, lastName, salary)"  + 
             "SELECT firstName, lastName, salary FROM old_employee";
Query query = session.createQuery(hql);
int result = query.executeUpdate();
System.out.println("Rows affected: " + result);

Aggregate Methods

HQL supports a range of aggregate methods, similar to SQL. They work the same way in HQL as in SQL and following is the list of the available functions:

S.N.FunctionsDescription
1avg(property name)The average of a property's value
2count(property name or *)The number of times a property occurs in the results
3max(property name)The maximum value of the property values
4min(property name)The minimum value of the property values
5sum(property name)The sum total of the property values

The distinct keyword only counts the unique values in the row set. The following query will return only unique count:

String hql = "SELECT count(distinct E.firstName) FROM Employee E";
Query query = session.createQuery(hql);
List results = query.list();

Pagination using Query

There are two methods of the Query interface for pagination.

S.N.Method & Description
1Query setFirstResult(int startPosition)

This method takes an integer that represents the first row in your result set, starting with row 0.

2Query setMaxResults(int maxResult)

This method tells Hibernate to retrieve a fixed number maxResults of objects.

Using above two methods together, we can construct a paging component in our web or Swing application. Following is the example which you can extend to fetch 10 rows at a time:

String hql = "FROM Employee";
Query query = session.createQuery(hql);
query.setFirstResult(1);
query.setMaxResults(10);
List results = query.list();



블로그 이미지

오픈이지 제로킴

시큐어코딩 교육/컨설팅 전문가 그룹

* Interceptor 와 Filter 의 차이점 





Spring MVC 요청 처리 흐름
Spring Handler Interceptors


1. 호출 시점이 다르다.

    둘다 컨트롤러가 호출되기 전에 호출되어 실행된다. 하지만  Filter는 Dispatcher가 호출되기전에, Interceptor는 Dispatcher가 호출되고 난뒤 호출된다.  

필터는 일반적으로 서블릿 컨테이너에서 제어하기 때문에 web.xml에서 정의하여야 하며, 스프링 애플리케이션에서 관리하는 빈을 DI로 받을 수 없다.

인터셉터는 dispatcher-servlet.xml 에서 컨트롤러에 대해 인터셉터를 정의하며, 스프링 애플리케이션에서 관리하는  빈을 DI로 받아서 사용한다.


2. 각 인터페이스에서 정의하고 있는 함수의 용도가 차이가 있다.

* Spring MVC 에서 interceptor 

org.springframework.web.servlet.HandlerInterceptor , 
org.springframework.web.servlet.handler.HandlerInterceptorAdapter 를 상속받아 Interceptor를 구현한다,

HandlerInterceptor 를 상속할 경우 다음 3가지 메서드를 재정의한다.

preHandle() :        Controller 가 수행되기 전에 호출된다.
                               처리결과에 따라 이후 Controller를 수행할지 여부를 boolean 으로 return 한다.
postHandle :         Controller 가 수행된후 View 를 호출하기 전에 호출된다.
afterCompletion : View 작업까지 완료된 후 호출된다. 
                               responseBody 를 이용할 경우 UI 에 이미 값을 전달후 해당 부분이 호출된다.

* Filter 
 - init() : 필터 인스턴스 초기화
 - doFilter() : 전/후 처리
 - destroy() : 필터 인스턴스 종료

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

throws IOException, ServletException { // 전 처리 chain.doFilter(request, response); // 후 처리 }




<참고> Filter에서 스프링DI를 사용하려면?
  <filter>
    <filter-name>restfulAuthFilter</filter-name>
    <filter-class>
      com.archnal.securityweb.web.RestfulAuthFilter
    </filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>utf-8</param-value>
    </init-param>
  </filter>
  
  <filter-mapping>
    <filter-name>restfulAuthFilter</filter-name>
    <url-pattern>/ws/rest/secure/*</url-pattern>
  </filter-mapping>
  

이런 경우 스프링컨텍스트의 DI를 이용해서 필터를 구현하고자 하는 경우에는 아래와 같이 web.xml 파일을 설정해야 한다.

  <filter>
    <filter-name>restfulAuthFilter</filter-name>
    
    <filter-class>
      org.springframework.web.filter.DelegatingFilterProxy
    </filter-class>

    <init-param>
      <param-name>encoding</param-name>
      <param-value>utf-8</param-value>
    </init-param>
  </filter>
  
  <filter-mapping>
    <filter-name>restfulAuthFilter</filter-name>
    <url-pattern>/ws/rest/secure/*</url-pattern>
  </filter-mapping>  


주의해야 할 점은 filter-name과 필터 클래스의 빈 이름이 동일해야 한다.

위의 필터의 타입레벨 annotation으로 @Service("restfulAuthFilter") 설정된 restfulAuthFilter가 filter-name으로 사용되어야 한다.

위와 같이 web.xml 파일을 설정하면 스프링의 DI를 이용하여 필터를 작성할 수 있다.


블로그 이미지

오픈이지 제로킴

시큐어코딩 교육/컨설팅 전문가 그룹

STEP1.  openeg 프로젝트에 스프링시큐리티3 라이브러리를 추가한다.


아래 3개파일을 /WEB-INF/lib 폴더로 다운로드 한다.


spring-security-3.2.3.RELEASE.zip



spring-security-config-3.0.0.RELEASE.jar

spring-security-core-3.0.0.RELEASE.jar 

spring-security-web-3.0.0.RELEASE.jar

spring-security-taglibs-3.0.0.RELEASE.jar




Spring-Security-3.0.zip

Spring-Security-Extensions.zip

Spring-Security-3.0-Dependencies.z01

Spring-Security-3.0-Dependencies.zip



STEP2.  /WEB-INF/openeg-security.xml 파일을 생성한다.

             

생성하기 어려우면 아래 첨부파일을 다운로드 받아 넣는다. ^^


openeg-security.xml



STEP3. /WEB-INF/web.xml 에 필터 추가

          

모두 요청에 대해 springSecurity가 적용되도록 필터를 설정한다.

아래 첨부파일을 다운로드 받아서 springSecurityFilterChain 부분만 복사해서 넣는다.

STEP2에 작성한 openeg-security.xml 이 springMVC 서블릿과 관련설정파일이 로드되기전에 추가로 로드되도록  ApplicationContext를 선언한다.

첨부된 web.xml 파일에서  <context-param> 설정 부분을 복사해서 사용한다.

web.xml


STEP4. 기본적인 설정완료!!

          

Spring Security 가 동작하는지 확인해보자. 서버를 구동하고 http://localhost:8080/openeg/test.jsp  페이지를 요청하면 기본적인 보안 레이어가 구현되어 인증화면이 나타는 것을 볼 수 있다.

사용자명과 비밀번호, 사용자역할을 openeg-security.xml 파일에서 하드코딩했다.

guest,guest로 로그인한다.


<authentication-manager alias="authenticationManager">

  <authentication-provider>

<user-service>

<user authorities="ROLE_USER" name="guest" 

                    password="guest"/>

</user-service>

   </authentication-provider>

</authentication-manager>



[추가적으로 해결해야 할 문제들]


1. 사용자계정을 이렇게는사용하기 힘들고(모든 계정을 XML파일에 등록할 수는 없으니^^) 데이터베이스 기반의 인증 프로바이더를 사용하여 해결한다.


2. 쇼핑몰이라면 로그인하지 않고 물건을 검색하는것이 가능해야 하는데 이예제는 이 사이트에 접속하면 무조건 "인증받아라"  구조이다.  이것은  사용자의 역할 정의를 통해서 해결한다.


3. 예제 사이트에 접속하면 무조건 밋밋한 로그인 페이지를 만나게 된다. 쇼핑몰이라면 헐~~ 이것다.  이건 로그인 폼을 추가해서 해결한다.






스프링 시큐리티 3  참고자료

http://www.javabeat.net/spring-security-3-0/



This article publishes the book excerpt from the book Spring Security 3.0.The following are the list of chapters in the book and brief description inside each chapters. If you are interested in receiving the future articles on book reviews and latest news on Java, please subscribe here.

Welcome to the world of Spring Security 3! I’m certainly pleased that you have acquired the first published book fully devoted to Spring Security, and i hope that it fulfills your every wish for a technical book on this fascinating subject. I’d like to use this introduction to set your expectations for the pages ahead, and give you some advice to help you along your way.

also read:

By the time you finish this book, you should feel comfortable with the architecture of Spring Security, the incorporation of Spring Security in a web-based application, and the integration of Spring Security with many types of external authentication and authorization systems.

The book is largely divided into two halves. The first half (Chapters 1-7) covers Spring Security as part of a web application from start to finish—very basic initial setup, all the way to advanced access control list security. The second half (Chapters 8-12) covers Spring Security as part of a larger software ecosystem, illustrating integration with common external systems such as OpenID, Microsoft Active Directory, and LDAP. The final chapter covers migration issues when moving from Spring Security 2 to Spring Security 3.

The book uses a simple Spring Web MVC based application to illustrate the concepts presented in the book. The application is intended to be very simple and straightforward, and purposely contains very little functionality—the goal of this application is to encourage you to focus on the Spring Security concepts, and not get tied up in the complexities of application development. You will have a much easier time following the book if you take the time to review the sample application source code, and try to follow along with the exercises. Some tips on getting started are in Chapter 1, Anatomy of an Unsafe Application and Appendix, Additional Reference Material.

What This Book Covers

Chapter 1, Anatomy of an Unsafe Application covers a hypothetical security audit of our e-commerce site, illustrating common issues that can be resolved through proper application of Spring Security. You will learn about some basic security terminology, and review some prerequisites for getting the sample application up and running.

Chapter 2, Getting Started with Spring Security reviews basic setup and configuration of form-based authentication with Spring Security, followed by a high-level overview of how Spring Security works from start to finish to secure web requests.

Chapter 3, Enhancing the User Experience illustrates additional user-facing functionality supported by Spring Security that can increase the usability of secured sites, including a remember me function, a styled login page, logout, and password change capability.

Chapter 4, Securing Credential Storage guides you through the key configuration steps required to secure your users’ information in a JDBC database, using Spring Security APIs. Important security concepts around safe password storage are also covered in this chapter.

Chapter 5, Fine-Grained Access Control covers in-page authorization checking (partial page rendering), and business-layer security using Spring Security’s method security capabilities.

Chapter 6, Advanced Configuration and Extension provides several hands-on walkthroughs of common customizations to Spring Security implementations, including custom servlet filters, custom authentication providers, and custom exception handling. Session fixation and concurrent session control are analyzed and appropriately applied to the site with required configuration steps reviewed. Finally, explicit bean-based configuration is clearly illustrated for all Spring Security functionality covered in the book.

Chapter 7, Access Control Lists teaches you the concepts and basic implementation of business object-level security using the Spring Security Access Control Lists module—a powerful module with very flexible applicability to challenging business security problems.

Chapter 8, Opening up to OpenID covers OpenID-enabled login and user information exchange, as well as a high-level overview of the logical flow of an OpenID-enabled system.

Chapter 9, LDAP Directory Services provides a guide to application integration with an LDAP directory server, including practical tips on different types of integrations with LDAP data.

Chapter 10, Single Sign On with Central Authentication Service shows how integration with Central Authentication Service (CAS) can provide single sign-on support to your Spring Security-enabled application.

Chapter 11, Client Certificate Authentication makes X.509 certificate-based authentication a clear alternative for certain business scenarios where managed certificates can add an additional layer of security to our application.

Chapter 12, Spring Security Extensions covers the Spring Security Kerberos extension project, which exposes a Kerberos integration layer for user authentication in our Spring Security application providing compatibility with a Unix Kerberos environment or Microsoft Active Directory.

Chapter 13, Migration to Spring Security 3 lays out the major differences between Spring Security 2 and Spring Security 3, including notable configuration changes, class and package migrations, and important new features. If you are familiar with Spring Security 2, we recommend that you read this chapter first, as it may make it easier to tie the examples back to code with which you are familiar.

Appendix, Additional Reference Material covers some reference material, which we feel is helpful (and largely undocumented) and too comprehensive to insert in the text of the chapters.

Securing Credential Storage

Up to this point, we’ve updated the JBCP Pets site with user-friendly functionality, including a custom login page, and change password and remember me features.

In this chapter, we’ll make a leap to a database-backed authentication store from the in-memory store we have used in the book until this point. We’ll explore the default expected Spring Security database schema, and will look into ways to extend JDBC implementation with customization.

During the course of this chapter, we’ll:

  • Understand how to configure Spring Security to utilize the services of a JDBC-accessible database to store and authenticate users
  • Learn how to configure a JDBC-compatible in-memory database using HSQLDB, for developer testing purposes
  • Work through the process of adapting Spring Security JDBC to an existing legacy schema
  • Examine two techniques for user and password management, both with out of the box and custom techniques
  • Examine different methods of configuring password encoding
  • Understand the password salting technique of providing additional security to stored passwords
  • Solve the problem of allowing user remember me tokens to persist even if the server restarts
  • Secure the application transport layer by understanding how to configure SSL/TLS encryption and port mapping

Database-backed authentication with Spring Security

An obvious issue with our more security-conscious implementation of JBCP Pets is that our in-memory storage of users and passwords is too short-lived to be user-friendly. As soon as the application is restarted, any new user registrations, password changes, or other activity will be lost. This isn’t acceptable, so the next logical implementation step when securing JBCP Pets will be to reconfigure Spring Security to utilize a relational database for user storage and authentication. The use of a JDBC-accessible relational database will allow user data to persist through application server restarts, and is more typical of real-world Spring Security use.

Configuring a database-resident authentication store

The first portion of this exercise involves setting up an instance of the Java-based relational database HyperSQL DB (or HSQL, for short), populated with the Spring Security default schema. We’ll configure HSQL to run in-memory using Spring 3′s embedded database configuration feature—a significantly simpler method of configuration than setting up the database by hand.

Keep in mind that in this example (and the remainder of the book), we’ll use HSQL, primarily, due to its ease of setup. We encourage you to tweak the configuration and use the database of your preference if you’re following along with the examples. As we didn’t want this portion of the book to focus on the complexities of database setup, we chose convenience over realism for the purposes of the exercises.

Creating the default Spring Security schema

We’ve supplied an SQL file, security-schema.sql, which will create all the tables required to implement Spring Security using HSQL. If you’re following along with your own database instance, you may have to adjust the schema definition syntax to fit your particular database. We’ll place this SQL file so that it’s on the classpath in WEB-INF/classes.

Configuring the HSQL embedded database

To configure the HSQL embedded database, we’ll modify the dogstore-security. xml file to both set up the database and run SQL to create the Spring Security table
structure. First, we’ll add a reference to the jdbc XML schema definition at the top of the file:

Next, we’ll declare the element, along with a reference to the SQL script:

1<jdbc:embedded-database id="dataSource" type="HSQL">
2    <jdbc:script location="classpath:security-schema.sql"/>
3</jdbc:embedded-database>

If you start the server at this point, you should be able to see the initialization of the HSQL database in the logs. Remember that the declaration creates this database only in the memory, so you won’t see anything on disk, and you won’t be able to use standard tools to query it.

Configuring JdbcDaoImpl authentication store

We’ll modify the dogstore-security.xml file to declare that we’re using a JDBC UserDetailsService implementation, instead of the Spring Security in-memory UserDetailsService that we configured in Chapter 2, Getting Started with Spring Security and Chapter 3, Enhancing the User Experience. This is done with a simple change to the declaration:

1<authentication-manager alias="authenticationManager">
2    <authentication-provider>
3        <b><jdbc-user-service data-source-ref="dataSource"/></b>
4    </authentication-provider>
5</authentication-manager>

The data-source-ref refers to the bean we declared using the shortcut declaration in the previous step.

Adding user definitions to the schema

Finally, we’ll create another SQL file that will get executed when the in-memory database is created. This SQL file will contain information about our default users, admin and guest, with the same GrantedAuthority settings that we’ve used in prior chapters. We’ll call this SQL file test-data.sql, and we’ll put it alongside security-schema.sql in WEB-INF/classes:

1insert into users(username, password, enabled) values
2    ('admin','admin',true);
3insert into authorities(username,authority) values
4    ('admin','ROLE_USER');
5insert into authorities(username,authority) values
6    ('admin','ROLE_ADMIN');
7insert into users(username, password, enabled) values
8    ('guest','guest',true);
9insert into authorities(username,authority) values
10    ('guest','ROLE_USER');
11commit;

Next, we’ll need to add this SQL file to the embedded database configuration so that it is loaded at startup:

1<jdbc:embedded-database id="dataSource" type="HSQL">
2    <jdbc:script location="classpath:security-schema.sql"/>
3    <b><jdbc:script location="classpath:test-data.sql"/></b>
4</jdbc:embedded-database>

After the SQL is added to the embedded database configuration, we should be able to start the application and log in. Spring Security is now looking at the database for authentication and GrantedAuthority information!

How database-backed authentication works

You may recall from our examination of the authentication process in Chapter 2 that the AuthenticationManager delegates to AuthenticationProvider to validate the credentials of the principal and ensure that it should be able to access the system at all. The AuthenticationProvider that we have been using in Chapters 2 and 3 was the DaoAuthenticationProvider. This provider delegates to a UserDetailsService implementation to retrieve and validate the information about the principal from the credential store. We can see this in the diagram from Chapter 2:

1As you may anticipate, the only meaningful difference between our configuration of a database-backed authentication store and the in-memory store is the implementation of the UserDetailsService. The o.s.s.core.userdetails. jdbc.JdbcDaoImpl class provides an implementation of a UserDetailsService. Instead of looking at an in-memory store (populated from the Spring Security XML configuration), the JdbcDaoImpl looks up users in a database.

2You may note that we didn’t reference the implementation class at all. This is because the declaration in the updated Spring Security
configuration will automatically configure the JdbcDaoImpl and wire it up to the AuthenticationProvider. Later in this chapter, we’ll see how to configure Spring Security to use our own implementation of JdbcDaoImpl, which continues to support the change password feature that we added to our custom InMemoryDaoImpl in Chapter 3. Let’s examine the configuration required to implement our own JdbcDaoImpl subclass that supports the change password function.

Implementing a custom JDBC UserDetailsService

As we did in one of the exercises in the previous chapter, we’ll take the baseline JdbcDaoImpl as our starting point, and extend it to support a change password function.

Creating a custom JDBC UserDetailsService class

Create the following class in the com.packtpub.springsecurity.security package:

1public class CustomJdbcDaoImpl extends JdbcDaoImpl implements
2IChangePassword {
3    public void changePassword(String username, String password) {
4        getJdbcTemplate()
5        update("UPDATE USERS SET PASSWORD = ? WHERE USERNAME = ?",
6            password, username);
7    }
8}

You can see that this simple class extends the default JdbcDaoImpl with a function to update the password in the database to the new password that the user ostensibly requested. We use standard Spring JDBC functionality to do this.

Adding a Spring Bean declaration for the custom UserDetailsService

Add the following Spring Bean declaration to the dogstore-base.xml Spring configuration file:

1<bean id="jdbcUserService"
2    class="com.packtpub.springsecurity.security.CustomJdbcDaoImpl">
3    <property name="dataSource" ref="dataSource"/>
4</bean>

Again, the dataSource Bean reference here resolves to the declaration we made to set up the HSQL in-memory database. You’ll observe that the custom UserDetailsService implementation allows us to tweak the interaction with the database significantly. We’ll use this capability to expand the baseline functionality of the UserDetailsService in later examples. This type of customization is very common in complex applications of Spring Security.

Out of the box JDBC-based user management

As our simple extension to JdbcDaoImpl illustrated, one might extend the class, while retaining the baseline functionality at the same time. But what if we wanted to implement more advanced features, such as user registration (a must for an online store!) and user management features, allowing site administrators to create users, update passwords, and so on?

Although these types of functions are relatively easy to write with additional JDBC statements, Spring Security actually provides out of the box functionality to support many common Create, Read, Update, and Delete (CRUD) operations on users in JDBC databases. This can be convenient for simple systems, and a good base to build on for any custom requirements that a user may have.

The implementation class o.s.s.provisioning.JdbcUserDetailsManager conveniently extends JdbcDaoImpl for us, and provides a number of
helpful user-related methods, declared as part of the o.s.s.provisioning. UserDetailsManager interface:

3As you can see, the changePassword method on JdbcUserDetailsManager precisely fits a gap in the functionality of our CustomJdbcDaoImpl class – it will verify the user’s existing password when changing it. Let’s review the configuration steps required to replace our CustomJdbcDaoImpl with the JdbcUserDetailsManager.

First, we’ll have to make need to declare the JdbcUserDetailsManager bean in dogstore-base.xml:

1<bean id="jdbcUserService"
2        class="org.springframework.security
3            .provisioning.JdbcUserDetailsManager">
4    <property name="dataSource" ref="dataSource"/>
5    <property name="authenticationManager"
6        ref="authenticationManager"/>
7</bean>

The reference to AuthenticationManager matches the alias we’ve previously declared in the element in dogstore-security.xml.
Don’t forget to comment out the declaration of the CustomJdbcDaoImpl bean—we will (temporarily) not be using it.

Next, we’ll have to make some minor adjustments to the changePassword.jsp page:

1<h2>Change Password</h2>
2    <form method="post">
3        <b><label for="oldpassword">Old Password</label>:
4        <input id="oldpassword" name="oldpassword"
5            size="20" maxlength="50" type="password"/>
6        <br /></b>
7        <label for="password">New Password</label>:
8        <input id="password" name="password" size="20"
9            maxlength="50" type="password"/>
10        <br />

Finally, we’ll have to make some minor adjustments to AccountController. Replace the @Autowired reference to the IChangePassword implementation with:

1@Autowired
2private UserDetailsManager userDetailsManager;

The submitChangePasswordPage also becomes much simpler, as we are relying on information about the current authenticated principal which the
JdbcUserDetailsManager determines on our behalf:

1public String submitChangePasswordPage(@RequestParam("oldpassword")
2        String oldPassword,
3    @RequestParam("password") String newPassword) {
4        userDetailsManager.changePassword(oldPassword, newPassword);
5        SecurityContextHolder.clearContext();
6        return "redirect:home.do";
7    }

Once these changes are complete, you can restart the web application and try out the new change password functionality!

Notice what happens when you don’t supply the correct password. Why do you think this happens? Try to think through how you’d adjust the behavior to make it more user friendly.

Although we won’t demonstrate all of the functionality supported by JdbcUserDetailsManager, we can see that it would be very easy to wire simple JSP pages (properly secured with authorization, of course!) to allow administrators to manage users of the site—essential for a production website!

Advanced configuration of JdbcDaoImpl

JdbcDaoImpl has a number of configuration options that allow for adapting its use to an existing schema, or for more sophisticated adjustment of its existing capabilities. In many cases, it’s possible to adapt the configuration of the out of the box JDBC UserDetailsService without having to write your own code.

One important feature is the ability to add a level of indirection between users and GrantedAuthority declarations by grouping GrantedAuthority into logical sets
called groups. Users are then assigned one or more groups, whose membership confers a set of GrantedAuthority declarations.

4As you see in the diagram, this indirection allows the assignment of the same set of roles to multiple users, by simply assigning any new users to existing groups. Contrast this with the behavior we’ve seen this far, where we assigned GrantedAuthority directly to individual users.

This bundling of common sets of authorities can be helpful in the following scenarios:

  • You need to segregate users into communities, with some overlapping roles between groups.
  • You want to globally change authorization for a class of user. For example, if you have a “supplier” group, you might want to enable or disable their access to particular portions of the application.
  • You have a large number of users, and you don’t need a user-level authority configuration.

Unless your application has a very small user base, there is a very high likelihood that you’ll be using group-based access control. The management ease and fl exibility of this rights management approach far outweighs the slightly greater complexity. This indirect technique of aggregating user privileges by group is commonly referred to as Group-Based Access Control (GBAC).

Group-based access control is an approach common to almost every
secured operating system or software package in the market. Microsoft
Active Directory (AD) is one of the most visible implementations of
large-scale GBAC, due to its design of slotting AD users into groups and
assignment of privileges to those groups. Management of privileges in
large AD-based organizations is made exponentially simpler through the
use of GBAC.
Try to think of the security models of the software you use—how are
users, groups, and privileges managed? What are the pros and cons of the
way the security model is written?

Let’s add a level of abstraction to JBCP Pets and apply the concept of group-based authorization to the site.

Configuring group-based authorization

We’ll add two groups to the website—regular users, which we’ll call “Users”, and administrative users, which we’ll call “Administrators”. Our existing guest and admin user accounts will be dropped into the appropriate groups through modifications to our SQL script that we use to set up the database.

Configuring JdbcDaoImpl to use groups

First, we must set properties on our JdbcDaoImpl custom subclass to enable the use of groups, and disable the use of direct authority granting to users. Add the following to the bean definition in dogstore-base.xml:

1<bean id="jdbcUserService"
2    class="com.packtpub.springsecurity.security.CustomJdbcDaoImpl">
3    <property name="dataSource" ref="dataSource"/>
4    <b><property name="enableGroups" value="true"/>
5    <property name="enableAuthorities" value="false"/></b>
6</bean>

Note that if you are following along and still have the code and configuration changes in place to utilize the JdbcUserManager, please revert them as we’ll be using the CustomJdbcDaoImpl for the remainder of this chapter.

Modifying the initial load SQL script

We’ll simply modify the SQL that we use to populate the database to:

  • Define our groups
  • Assign GrantedAuthority specifications to groups
  • Assign users to groups

For simplicity, we’ll create a new SQL script called test-users-groups-data.sql. We’ll add the groups first:

1insert into groups(group_name) values ('Users');
2insert into groups(group_name) values ('Administrators');

Next, assign roles to groups:

1insert into group_authorities(group_id, authority) select id,'ROLE_
2USER' from groups where group_name='Users';
3insert into group_authorities(group_id, authority) select id,'ROLE_
4USER' from groups where group_name='Administrators';
5insert into group_authorities(group_id, authority) select id,'ROLE_
6ADMIN' from groups where group_name='Administrators';

Next, create the users:

1insert into users(username, password, enabled) values
2('admin','admin',true);
3insert into users(username, password, enabled) values
4('guest','guest',true);

Finally, assign users to groups:

1insert into group_members(group_id, username) select id,'guest' from
2groups where group_name='Users';
3insert into group_members(group_id, username) select id,'admin' from
4groups where group_name='Administrators';

Modifying the embedded database creation declaration

We’ll need to update the creation of our embedded HSQL database to reference this script in lieu of the existing test-data.sql script:

1<jdbc:embedded-database id="dataSource" type="HSQL">
2    <jdbc:script location="classpath:security-schema.sql"/>
3    <b><jdbc:script location="classpath:test-users-groups-data.sql"/></b>
4</jdbc:embedded-database>

Note that the security-schema.sql already contains declarations for the tables required to support the group structure, so we don’t need to modify that script.

At this point, you should be able to start the JBCP Pets site again and it will behave just as before; however, the additional layer of abstraction between users and privileges will enable us to develop some sophisticated user management functionality in later exercises with a fraction of effort.

Let’s step away from the JBCP Pets scenario for a moment and cover one more important bit of configuration while we’re in this area.

Using a legacy or custom schema with database-resident authentication

It’s common for new users of Spring Security to begin their experience by adapting the JDBC user, group, or role mapping to an existing schema. Even though a legacy database doesn’t conform to the expected Spring Security schema, we can still configure the JdbcDaoImpl to map to it. Imagine we have an existing legacy database schema similar to the following figure, onto which we are going to implement Spring Security.

5We can easily change the configuration of JdbcDaoImpl to utilize this schema and override the Spring Security expected table definitions and columns that we’re using for JBCP Pets.

Determining the correct JDBC SQL queries

JdbcDaoImpl has three SQL queries which have a well-defined parameter and set of returned columns. We must determine the SQL that we’ll assign to each of these queries, based on its intended functionality. Each SQL query used by the JdbcDaoImpl takes the username presented at login as its one and only parameter.

67Be aware that in some cases, the return columns are not used by the default JdbcDaoImpl implementation, but they must be returned anyway. Spend some time now trying to write these queries for the database diagram on the previous page before moving on to the next step.

Configuring the JdbcDaoImpl to use custom SQL queries

In order to use the custom SQL queries for our non-standard schema, we’ll simply configure the JdbcDaoImpl properties in the Spring Bean configuration file. Note that in order to configure the JDBC queries on JdbcDaoImpl, you cannot use the declaration. You must explicitly instantiate the bean, as we’ve done with our custom JdbcDaoImpl.

1<bean id="jdbcUserService"
2    class="com.packtpub.springsecurity.security.CustomJdbcDaoImpl">
3    <property name="dataSource" ref="dataSource"/>
4    <property name="enableGroups" value="true"/>
5    <property name="enableAuthorities" value="false"/>
6    <b><property name="usersByUsernameQuery">
7        <value>SELECT LOGIN, PASSWORD,
8            1 FROM USER_INFO WHERE LOGIN = ?
9        </value>
10    </property>
11    <property name="groupAuthoritiesByUsernameQuery">
12        <value>SELECT G.GROUP_ID, G.GROUP_NAME, P.NAME
13            FROM USER_INFO U
14            JOIN USER_GROUP UG on U.USER_INFO_ID = UG.USER_INFO_ID
15            JOIN GROUP G ON UG.GROUP_ID = G.GROUP_ID