This commit is contained in:
Ahmed Tawila 2017-10-23 10:58:32 +02:00
commit c768592435
81 changed files with 771 additions and 333 deletions

View File

@ -11,3 +11,6 @@
- [String Search Algorithms for Large Texts](http://www.baeldung.com/java-full-text-search-algorithms)
- [Test a Linked List for Cyclicity](http://www.baeldung.com/java-linked-list-cyclicity)
- [Binary Search Algorithm in Java](http://www.baeldung.com/java-binary-search)
- [Bubble Sort in Java](http://www.baeldung.com/java-bubble-sort)
- [Introduction to JGraphT](http://www.baeldung.com/jgrapht)
- [Introduction to Minimax Algorithm](http://www.baeldung.com/java-minimax-algorithm)

View File

@ -19,11 +19,13 @@ public class BubbleSort {
void optimizedBubbleSort(Integer[] arr) {
int i = 0, n = arr.length;
boolean swapNeeded = true;
while (i < n - 1 && swapNeeded) {
swapNeeded = false;
for (int j = i + 1; j < n - i; j++) {
for (int j = 1; j < n - i; j++) {
if (arr[j - 1] > arr[j]) {
int temp = arr[j - 1];
arr[j - 1] = arr[j];
arr[j] = temp;

View File

@ -1,92 +0,0 @@
package algorithms;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import com.baeldung.algorithms.mcts.montecarlo.MonteCarloTreeSearch;
import com.baeldung.algorithms.mcts.montecarlo.State;
import com.baeldung.algorithms.mcts.montecarlo.UCT;
import com.baeldung.algorithms.mcts.tictactoe.Board;
import com.baeldung.algorithms.mcts.tictactoe.Position;
import com.baeldung.algorithms.mcts.tree.Tree;
public class MCTSTest {
Tree gameTree;
MonteCarloTreeSearch mcts;
@Before
public void initGameTree() {
gameTree = new Tree();
mcts = new MonteCarloTreeSearch();
}
@Test
public void givenStats_whenGetUCTForNode_thenUCTMatchesWithManualData() {
double uctValue = 15.79;
assertEquals(UCT.uctValue(600, 300, 20), uctValue, 0.01);
}
@Test
public void giveninitBoardState_whenGetAllPossibleStates_thenNonEmptyList() {
State initState = gameTree.getRoot().getState();
List<State> possibleStates = initState.getAllPossibleStates();
assertTrue(possibleStates.size() > 0);
}
@Test
public void givenEmptyBoard_whenPerformMove_thenLessAvailablePossitions() {
Board board = new Board();
int initAvailablePositions = board.getEmptyPositions().size();
board.performMove(Board.P1, new Position(1, 1));
int availablePositions = board.getEmptyPositions().size();
assertTrue(initAvailablePositions > availablePositions);
}
@Test
public void givenEmptyBoard_whenSimulateInterAIPlay_thenGameDraw() {
Board board = new Board();
int player = Board.P1;
int totalMoves = Board.DEFAULT_BOARD_SIZE * Board.DEFAULT_BOARD_SIZE;
for (int i = 0; i < totalMoves; i++) {
board = mcts.findNextMove(board, player);
if (board.checkStatus() != -1) {
break;
}
player = 3 - player;
}
int winStatus = board.checkStatus();
assertEquals(winStatus, Board.DRAW);
}
@Test
public void givenEmptyBoard_whenLevel1VsLevel3_thenLevel3WinsOrDraw() {
Board board = new Board();
MonteCarloTreeSearch mcts1 = new MonteCarloTreeSearch();
mcts1.setLevel(1);
MonteCarloTreeSearch mcts3 = new MonteCarloTreeSearch();
mcts3.setLevel(3);
int player = Board.P1;
int totalMoves = Board.DEFAULT_BOARD_SIZE * Board.DEFAULT_BOARD_SIZE;
for (int i = 0; i < totalMoves; i++) {
if (player == Board.P1)
board = mcts3.findNextMove(board, player);
else
board = mcts1.findNextMove(board, player);
if (board.checkStatus() != -1) {
break;
}
player = 3 - player;
}
int winStatus = board.checkStatus();
assertTrue(winStatus == Board.DRAW || winStatus == Board.P1);
}
}

View File

@ -1 +1,3 @@
## Relevant articles:
[Introduction to Animal Sniffer Maven Plugin](http://www.baeldung.com/maven-animal-sniffer)

View File

@ -1 +1,4 @@
## Relevant articles:
- [Advanced Querying in Apache Cayenne](http://www.baeldung.com/apache-cayenne-query)
- [Introduction to Apache Cayenne ORM](http://www.baeldung.com/apache-cayenne-orm)

View File

@ -1,2 +1,5 @@
## Relevant Articles:
- [Introduction to Apache CXF Aegis Data Binding](http://www.baeldung.com/aegis-data-binding-in-apache-cxf)
- [Apache CXF Support for RESTful Web Services](http://www.baeldung.com/apache-cxf-rest-api)
- [A Guide to Apache CXF with Spring](http://www.baeldung.com/apache-cxf-with-spring)
- [Introduction to Apache CXF](http://www.baeldung.com/introduction-to-apache-cxf)

44
apache-spark/pom.xml Normal file
View File

@ -0,0 +1,44 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung</groupId>
<artifactId>apache-spark</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>apache-spark</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.spark/spark-core_2.10 -->
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.10</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,53 @@
package com.baeldung;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.*;
import org.apache.spark.api.java.function.Function2;
import org.apache.spark.api.java.function.PairFunction;
import scala.Tuple2;
public class WordCount {
private static final Pattern SPACE = Pattern.compile(" ");
public static void main(String[] args) throws Exception {
if (args.length < 1) {
System.err.println("Usage: JavaWordCount <file>");
System.exit(1);
}
SparkConf sparkConf = new SparkConf().setAppName("JavaWordCount").setMaster("local");
JavaSparkContext ctx = new JavaSparkContext(sparkConf);
JavaRDD<String> lines = ctx.textFile(args[0], 1);
JavaRDD<String> words = lines.flatMap(s -> Arrays.asList(SPACE.split(s)).iterator());
JavaPairRDD<String, Integer> ones = words.mapToPair(
new PairFunction<String, String, Integer>() {
@Override
public Tuple2<String, Integer> call(String s) {
return new Tuple2<>(s, 1);
}
});
JavaPairRDD<String, Integer> counts = ones.reduceByKey(
new Function2<Integer, Integer, Integer>() {
@Override
public Integer call(Integer i1, Integer i2) {
return i1 + i2;
}
});
List<Tuple2<String, Integer>> output = counts.collect();
for (Tuple2<?, ?> tuple : output) {
System.out.println(tuple._1() + ": " + tuple._2());
}
ctx.stop();
}
}

View File

@ -0,0 +1,3 @@
Hello from Baeldung
Keep Learning Spark
Bye from Baeldung

View File

@ -1 +1,3 @@
## Relevant articles:
- [Introduction to Atomix](http://www.baeldung.com/atomix)

View File

@ -1,3 +1,6 @@
### Relevant articles
- [AWS Lambda Using DynamoDB With Java](http://www.baeldung.com/aws-lambda-dynamodb-java)
- [AWS S3 with Java](http://www.baeldung.com/aws-s3-java)
- [AWS Lambda With Java](http://www.baeldung.com/java-aws-lambda)

View File

@ -13,3 +13,7 @@ and a BODY Payload like {"id": 1,"name": "World"}
and we will get a return code of 201 and the response: Hello, World - if the transform() method from Application class is uncommented and the process() method is commented
or return code of 201 and the response: {"id": 10,"name": "Hello, World"} - if the transform() method from Application class is commented and the process() method is uncommented
## Relevant articles:
- [Apache Camel with Spring Boot](http://www.baeldung.com/apache-camel-spring-boot)

View File

@ -71,8 +71,5 @@ public class URIvsURLUnitTest {
URL url = new URL("http://courses.baeldung.com");
String contents = IOUtils.toString(url.openStream());
assertTrue(contents.contains("<!DOCTYPE html>"));
}
}

View File

@ -1,3 +1,4 @@
### Relevant Articles:
[Introduction to Drools](http://www.baeldung.com/drools)
[Drools Using Rules from Excel Files](http://www.baeldung.com/drools-excel)
- [Introduction to Drools](http://www.baeldung.com/drools)
- [Drools Using Rules from Excel Files](http://www.baeldung.com/drools-excel)
- [Drools Using Rules from Excel Files](http://www.baeldung.com/drools-excel)

View File

@ -5,4 +5,6 @@ This is the implementation of a [spring-hypermedia-api][1] client using Feign.
[1]: https://github.com/eugenp/spring-hypermedia-api
### Relevant Articles:
- [Intro to Feign](http://www.baeldung.com/intro-to-feign)
- [Introduction to SLF4J](http://www.baeldung.com/slf4j-with-log4j2-logback)

View File

@ -1 +1,3 @@
## Relevant articles:
- [Introduction to GraphQL](http://www.baeldung.com/graphql)

View File

@ -1,3 +1,4 @@
### Relevant articles:
- [New Stream, Comparator and Collector Functionality in Guava 21](http://www.baeldung.com/guava-21-new)
- [New in Guava 21 common.util.concurrent](http://www.baeldung.com/guava-21-util-concurrent)
- [Zipping Collections in Java](http://www.baeldung.com/java-collections-zip)

View File

@ -1,3 +1,4 @@
### Relevant Articles:
- [Cachable Static Assets with Spring MVC](http://www.baeldung.com/cachable-static-assets-with-spring-mvc)
- [Minification of JS and CSS Assets with Maven](http://www.baeldung.com/maven-minification-of-js-and-css-assets)
- [Serve Static Resources with Spring](http://www.baeldung.com/spring-mvc-static-resources)

View File

@ -20,3 +20,5 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
- [HttpAsyncClient Tutorial](http://www.baeldung.com/httpasyncclient-tutorial)
- [HttpClient 4 Tutorial](http://www.baeldung.com/httpclient-guide)
- [Advanced HttpClient Configuration](http://www.baeldung.com/httpclient-advanced-config)
- [HttpClient 4 Do Not Follow Redirects](http://www.baeldung.com/httpclient-stop-follow-redirect)
- [HttpClient 4 Setting a Custom User-Agent](http://www.baeldung.com/httpclient-user-agent-header)

View File

@ -28,3 +28,10 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
- [A Guide to Optional with Jackson](http://www.baeldung.com/jackson-optional)
- [Map Serialization and Deserialization with Jackson](http://www.baeldung.com/jackson-map)
- [Jackson Streaming API](http://www.baeldung.com/jackson-streaming-api)
- [Jackson JsonMappingException (No serializer found for class)](http://www.baeldung.com/jackson-jsonmappingexception)
- [How To Serialize Enums as JSON Objects with Jackson](http://www.baeldung.com/jackson-serialize-enums)
- [Jackson Marshall String to JsonNode](http://www.baeldung.com/jackson-json-to-jsonnode)
- [Ignore Null Fields with Jackson](http://www.baeldung.com/jackson-ignore-null-fields)
- [Jackson Unmarshall to Collection/Array](http://www.baeldung.com/jackson-collection-array)
- [Jackson Change Name of Field](http://www.baeldung.com/jackson-name-of-property)
- [Serialize Only Fields that meet a Custom Criteria with Jackson](http://www.baeldung.com/jackson-serialize-field-custom-criteria)

View File

@ -129,7 +129,7 @@
<properties>
<!-- marshalling -->
<jackson.version>2.9.0</jackson.version>
<jackson.version>2.9.2</jackson.version>
<!-- util -->
<guava.version>19.0</guava.version>

View File

@ -0,0 +1,70 @@
package com.baeldung.jackson.deserialization.nested;
import static org.junit.Assert.*;
import java.io.IOException;
import org.junit.Test;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
public class DeserializeWithNestedPropertiesUnitTest {
private String SOURCE_JSON = "{\"id\":\"957c43f2-fa2e-42f9-bf75-6e3d5bb6960a\",\"name\":\"The Best Product\",\"brand\":{\"id\":\"9bcd817d-0141-42e6-8f04-e5aaab0980b6\",\"name\":\"ACME Products\",\"owner\":{\"id\":\"b21a80b1-0c09-4be3-9ebd-ea3653511c13\",\"name\":\"Ultimate Corp, Inc.\"}}}";
@Test
public void whenUsingJacksonAnnotations_thenOk() throws IOException {
Product product = new ObjectMapper().readerFor(Product.class)
.readValue(SOURCE_JSON);
assertEquals(product.getName(), "The Best Product");
assertEquals(product.getBrandName(), "ACME Products");
assertEquals(product.getOwnerName(), "Ultimate Corp, Inc.");
}
@Test
public void whenUsingJacksonJsonNode_thenOk() throws IOException {
JsonNode productNode = new ObjectMapper().readTree(SOURCE_JSON);
Product product = new Product();
product.setId(productNode.get("id")
.textValue());
product.setName(productNode.get("name")
.textValue());
product.setBrandName(productNode.get("brand")
.get("name")
.textValue());
product.setOwnerName(productNode.get("brand")
.get("owner")
.get("name")
.textValue());
assertEquals(product.getName(), "The Best Product");
assertEquals(product.getBrandName(), "ACME Products");
assertEquals(product.getOwnerName(), "Ultimate Corp, Inc.");
}
@Test
public void whenUsingJacksonDeserializerManuallyRegistered_thenOk() throws IOException {
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Product.class, new ProductDeserializer());
mapper.registerModule(module);
Product product = mapper.readValue(SOURCE_JSON, Product.class);
assertEquals(product.getName(), "The Best Product");
assertEquals(product.getBrandName(), "ACME Products");
assertEquals(product.getOwnerName(), "Ultimate Corp, Inc.");
}
@Test
public void whenUsingJacksonDeserializerAutoRegistered_thenOk() throws IOException {
ObjectMapper mapper = new ObjectMapper();
Product product = mapper.readValue(SOURCE_JSON, Product.class);
assertEquals(product.getName(), "The Best Product");
assertEquals(product.getBrandName(), "ACME Products");
assertEquals(product.getOwnerName(), "Ultimate Corp, Inc.");
}
}

View File

@ -0,0 +1,55 @@
package com.baeldung.jackson.deserialization.nested;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
@JsonDeserialize(using = ProductDeserializer.class)
public class Product {
private String id;
private String name;
private String brandName;
private String ownerName;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBrandName() {
return brandName;
}
public void setBrandName(String brandName) {
this.brandName = brandName;
}
public String getOwnerName() {
return ownerName;
}
public void setOwnerName(String ownerName) {
this.ownerName = ownerName;
}
@SuppressWarnings("unchecked")
@JsonProperty("brand")
private void unpackNested(Map<String, Object> brand) {
this.brandName = (String) brand.get("name");
Map<String, String> owner = (Map<String, String>) brand.get("owner");
this.ownerName = owner.get("name");
}
}

View File

@ -0,0 +1,40 @@
package com.baeldung.jackson.deserialization.nested;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
@SuppressWarnings("serial")
public class ProductDeserializer extends StdDeserializer<Product> {
public ProductDeserializer() {
this(null);
}
public ProductDeserializer(Class<?> vc) {
super(vc);
}
@Override
public Product deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
JsonNode productNode = jp.getCodec()
.readTree(jp);
Product product = new Product();
product.setId(productNode.get("id")
.textValue());
product.setName(productNode.get("name")
.textValue());
product.setBrandName(productNode.get("brand")
.get("name")
.textValue());
product.setOwnerName(productNode.get("brand")
.get("owner")
.get("name")
.textValue());
return product;
}
}

View File

@ -7,3 +7,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
### Relevant Articles:
- [Java Bean Validation Basics](http://www.baeldung.com/javax-validation)
- [Validating Container Elements with Bean Validation 2.0](http://www.baeldung.com/bean-validation-container-elements)

View File

@ -1 +1,4 @@
## Relevant articles:
- [JHipster with a Microservice Architecture](http://www.baeldung.com/jhipster-microservices)
- [Intro to JHipster](http://www.baeldung.com/jhipster)

View File

@ -43,3 +43,7 @@ Available commands (assumes httpie - https://github.com/jkbrzt/httpie):
```
The Baeldung post that compliments this repo can be found [here](http://www.baeldung.com/)
## Relevant articles:
- [Supercharge Java Authentication with JSON Web Tokens (JWTs)](http://www.baeldung.com/java-json-web-tokens-jjwt)

View File

@ -1 +1,3 @@
## Relevant articles:
- [Microbenchmarking with Java](http://www.baeldung.com/java-microbenchmark-harness)

View File

@ -1 +1,3 @@
## Relevant articles:
- [Introduction to Jooby Project](http://www.baeldung.com/jooby)

View File

@ -1 +1,3 @@
## Relevant articles:
- [Introduction to JsonPath](http://www.baeldung.com/guide-to-jayway-jsonpath)

View File

@ -1,2 +1,4 @@
### Relevant articles
- [Introduction to Reladomo](http://www.baeldung.com/reladomo)
- [Introduction to ORMLite](http://www.baeldung.com/ormlite)
- [Introduction To Kryo](http://www.baeldung.com/kryo)

View File

@ -8,9 +8,9 @@
- [Embedded Jetty Server in Java](http://www.baeldung.com/jetty-embedded)
- [Introduction to Apache Flink with Java](http://www.baeldung.com/apache-flink)
- [Introduction to JSONassert](http://www.baeldung.com/jsonassert)
- [Intro to JaVer](http://www.baeldung.com/javers)
- [Intro to JaVers](http://www.baeldung.com/javers)
- [Introduction to Apache Commons Math](http://www.baeldung.com/apache-commons-math)
- [Intro to JaVer](http://www.baeldung.com/serenity-bdd)
- [Intro to Serenity BDD](http://www.baeldung.com/serenity-bdd)
- [Introduction to Netty](http://www.baeldung.com/netty)
- [Merging Streams in Java](http://www.baeldung.com/java-merge-streams)
- [Serenity BDD and Screenplay](http://www.baeldung.com/serenity-screenplay)
@ -53,6 +53,7 @@
- [Using Pairs in Java](http://www.baeldung.com/java-pairs)
- [Apache Commons Collections Bag](http://www.baeldung.com/apache-commons-bag)
- [Introduction to Caffeine](http://www.baeldung.com/java-caching-caffeine)
+-[Introduction to Chronicle Queue](http://www.baeldung.com/java-chronicle-queue)
The libraries module contains examples related to small libraries that are relatively easy to use and does not require any separate module of its own.

View File

@ -1 +1,3 @@
## Relevant articles:
- [Guide to LinkRest](http://www.baeldung.com/linkrest)

View File

@ -1 +1,7 @@
## Relevant articles:
- [Introduction to MockServer](http://www.baeldung.com/mockserver)
- [JMockit Advanced Usage](http://www.baeldung.com/jmockit-advanced-usage)
- [A Guide to JMockit Expectations](http://www.baeldung.com/jmockit-expectations)
- [JMockit 101](http://www.baeldung.com/jmockit-101)
- [Mockito vs EasyMock vs JMockit](http://www.baeldung.com/mockito-vs-easymock-vs-jmockit)

View File

@ -1 +1,3 @@
## Relevant articles:
- [Introduction to MockServer](http://www.baeldung.com/mockserver)

View File

@ -1 +1,3 @@
## Relevant articles:
- [List of Rules Engines in Java](http://www.baeldung.com/java-rule-engines)

View File

@ -1 +1,3 @@
## Relevant articles:
- [JIRA REST API Integration](http://www.baeldung.com/jira-rest-api)

View File

@ -1 +1,3 @@
## Relevant articles:
- [Drools Spring Integration](http://www.baeldung.com/drools-spring-integration)

View File

@ -1 +1,7 @@
## Relevant articles:
- [Guide to UriComponentsBuilder in Spring](http://www.baeldung.com/spring-uricomponentsbuilder)
- [Returning Custom Status Codes from Spring Controllers](http://www.baeldung.com/spring-mvc-controller-custom-http-status-code)
- [The Guide to RestTemplate](http://www.baeldung.com/rest-template)
- [Spring RequestMapping](http://www.baeldung.com/spring-requestmapping)
- [ETags for REST with Spring](http://www.baeldung.com/etags-for-rest-with-spring)

View File

@ -8,7 +8,10 @@ The "REST With Spring" Classes: http://github.learnspringsecurity.com
### Relevant Articles:
- [Spring Security Remember Me](http://www.baeldung.com/spring-security-remember-me)
- [Redirect to different pages after Login with Spring Security](http://www.baeldung.com/spring_redirect_after_login)
- [Changing Spring Model Parameters with Handler Interceptor](http://www.baeldung.com/spring-model-parameters-with-handler-interceptor)
- [Introduction to Spring MVC HandlerInterceptor](http://www.baeldung.com/spring-mvc-handlerinterceptor)
- [Using a Custom Spring MVCs Handler Interceptor to Manage Sessions](http://www.baeldung.com/spring-mvc-custom-handler-interceptor)
- [A Guide to CSRF Protection in Spring Security](http://www.baeldung.com/spring-security-csrf)
### Build the Project
```

View File

@ -113,6 +113,40 @@
<!-- <version>3.0.1</version> -->
<!-- </dependency> -->
<!-- util -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-databind.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<!-- test -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${org.springframework.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<version>${org.springframework.security.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
@ -174,6 +208,7 @@
<!-- util -->
<guava.version>19.0</guava.version>
<commons-lang3.version>3.5</commons-lang3.version>
<jackson-databind.version>2.9.1</jackson-databind.version>
<httpclient.version>4.5.2</httpclient.version>
<httpcore.version>4.4.5</httpcore.version>

View File

@ -1,9 +1,14 @@
package org.baeldung.spring;
import org.baeldung.web.interceptor.LoggerInterceptor;
import org.baeldung.web.interceptor.SessionTimerInterceptor;
import org.baeldung.web.interceptor.UserInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@ -11,6 +16,7 @@ import org.springframework.web.servlet.view.JstlView;
@EnableWebMvc
@Configuration
@ComponentScan("org.baeldung.web.controller")
public class MvcConfig extends WebMvcConfigurerAdapter {
public MvcConfig() {
@ -28,6 +34,7 @@ public class MvcConfig extends WebMvcConfigurerAdapter {
registry.addViewController("/login.html");
registry.addViewController("/homepage.html");
registry.addViewController("/console.html");
registry.addViewController("/csrfHome.html");
}
@Bean
@ -40,4 +47,11 @@ public class MvcConfig extends WebMvcConfigurerAdapter {
return bean;
}
@Override
public void addInterceptors(final InterceptorRegistry registry) {
registry.addInterceptor(new LoggerInterceptor());
registry.addInterceptor(new UserInterceptor());
registry.addInterceptor(new SessionTimerInterceptor());
}
}

View File

@ -12,7 +12,6 @@ import org.springframework.web.bind.annotation.ResponseStatus;
// to test csrf
@Controller
@RequestMapping(value = "/auth/")
public class BankController {
private final Logger logger = LoggerFactory.getLogger(getClass());

View File

@ -0,0 +1,59 @@
package org.baeldung.web.controller;
import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
import java.util.Arrays;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.baeldung.web.dto.Foo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.util.UriComponentsBuilder;
@Controller
@RequestMapping(value = "/auth/foos")
public class FooController {
@Autowired
private ApplicationEventPublisher eventPublisher;
public FooController() {
super();
}
// API
// read - single
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
@ResponseBody
public Foo findById(@PathVariable("id") final Long id, final UriComponentsBuilder uriBuilder, final HttpServletResponse response) {
return new Foo(randomAlphabetic(6));
}
// read - multiple
@RequestMapping(method = RequestMethod.GET)
@ResponseBody
public List<Foo> findAll() {
return Arrays.asList(new Foo(randomAlphabetic(6)));
}
// write - just for test
@RequestMapping(method = RequestMethod.POST)
@ResponseStatus(HttpStatus.CREATED)
@ResponseBody
public Foo create(@RequestBody final Foo foo) {
return foo;
}
}

View File

@ -0,0 +1,80 @@
package org.baeldung.web.dto;
import java.io.Serializable;
public class Foo implements Serializable {
private long id;
private String name;
public Foo() {
super();
}
public Foo(final String name) {
super();
this.name = name;
}
// API
public long getId() {
return id;
}
public void setId(final long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
//
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Foo other = (Foo) obj;
if (name == null) {
if (other.name != null) {
return false;
}
} else if (!name.equals(other.name)) {
return false;
}
return true;
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("Foo [name=")
.append(name)
.append("]");
return builder.toString();
}
}

View File

@ -33,4 +33,8 @@
</authentication-provider>
</authentication-manager>
<!-- <mvc:interceptors>
<bean id="loggerInterceptor" class="org.baeldung.web.interceptor.LoggerInterceptor" />
</mvc:interceptors> -->
</beans:beans>

View File

@ -5,7 +5,7 @@ import static org.springframework.security.test.web.servlet.request.SecurityMock
import javax.servlet.Filter;
import org.baeldung.persistence.model.Foo;
import org.baeldung.web.dto.Foo;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
@ -14,15 +14,15 @@ import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.RequestPostProcessor;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.WebApplicationContext;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@Transactional
public abstract class CsrfAbstractIntegrationTest {
@Autowired

View File

@ -0,0 +1,25 @@
package org.baeldung.security.csrf;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.baeldung.security.spring.SecurityWithoutCsrfConfig;
import org.baeldung.spring.MvcConfig;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
@ContextConfiguration(classes = { SecurityWithoutCsrfConfig.class, MvcConfig.class })
public class CsrfDisabledIntegrationTest extends CsrfAbstractIntegrationTest {
@Test
public void givenNotAuth_whenAddFoo_thenUnauthorized() throws Exception {
mvc.perform(post("/auth/foos").contentType(MediaType.APPLICATION_JSON).content(createFoo())).andExpect(status().isUnauthorized());
}
@Test
public void givenAuth_whenAddFoo_thenCreated() throws Exception {
mvc.perform(post("/auth/foos").contentType(MediaType.APPLICATION_JSON).content(createFoo()).with(testUser())).andExpect(status().isCreated());
}
}

View File

@ -5,13 +5,12 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.baeldung.security.spring.SecurityWithCsrfConfig;
import org.baeldung.spring.PersistenceConfig;
import org.baeldung.spring.WebConfig;
import org.baeldung.spring.MvcConfig;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
@ContextConfiguration(classes = { SecurityWithCsrfConfig.class, PersistenceConfig.class, WebConfig.class })
@ContextConfiguration(classes = { SecurityWithCsrfConfig.class, MvcConfig.class })
public class CsrfEnabledIntegrationTest extends CsrfAbstractIntegrationTest {
@Test

View File

@ -1,8 +1,5 @@
package org.baeldung.security.spring;
import org.baeldung.web.error.CustomAccessDeniedHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
@ -12,14 +9,10 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableAutoConfiguration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityWithCsrfConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomAccessDeniedHandler accessDeniedHandler;
public SecurityWithCsrfConfig() {
super();
}
@ -46,8 +39,6 @@ public class SecurityWithCsrfConfig extends WebSecurityConfigurerAdapter {
.and()
.httpBasic()
.and()
.exceptionHandling().accessDeniedHandler(accessDeniedHandler)
.and()
.headers().cacheControl().disable()
;
// @formatter:on

View File

@ -1,8 +1,5 @@
package org.baeldung.security.spring;
import org.baeldung.web.error.CustomAccessDeniedHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
@ -12,16 +9,10 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableAutoConfiguration
//
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
// @ImportResource({ "classpath:webSecurityConfig.xml" })
public class SecurityWithoutCsrfConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomAccessDeniedHandler accessDeniedHandler;
public SecurityWithoutCsrfConfig() {
super();
}
@ -42,18 +33,15 @@ public class SecurityWithoutCsrfConfig extends WebSecurityConfigurerAdapter {
protected void configure(final HttpSecurity http) throws Exception {
// @formatter:off
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/auth/admin/*").hasRole("ADMIN")
.antMatchers("/auth/*").hasAnyRole("ADMIN","USER")
.antMatchers("/*").permitAll()
.antMatchers("/auth/admin/*").hasAnyRole("ROLE_ADMIN")
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
// .exceptionHandling().accessDeniedPage("/my-error-page")
.exceptionHandling().accessDeniedHandler(accessDeniedHandler)
.and()
.headers().cacheControl().disable()
.and()
.csrf().disable()
;
// @formatter:on
}

View File

@ -4,8 +4,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.baeldung.security.spring.SecurityWithoutCsrfConfig;
import org.baeldung.spring.PersistenceConfig;
import org.baeldung.spring.WebConfig;
import org.baeldung.spring.MvcConfig;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -16,13 +15,11 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.WebApplicationContext;
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@Transactional
@ContextConfiguration(classes = { SecurityWithoutCsrfConfig.class, PersistenceConfig.class, WebConfig.class })
@ContextConfiguration(classes = { SecurityWithoutCsrfConfig.class, MvcConfig.class })
public class LoggerInterceptorIntegrationTest {
@Autowired
@ -46,7 +43,8 @@ public class LoggerInterceptorIntegrationTest {
*/
@Test
public void testInterceptors() throws Exception {
mockMvc.perform(get("/graph.html")).andExpect(status().isOk());
mockMvc.perform(get("/login.html"))
.andExpect(status().isOk());
}
}

View File

@ -6,8 +6,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import javax.servlet.http.HttpSession;
import org.baeldung.security.spring.SecurityWithoutCsrfConfig;
import org.baeldung.spring.PersistenceConfig;
import org.baeldung.spring.WebConfig;
import org.baeldung.spring.MvcConfig;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -20,13 +19,11 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.WebApplicationContext;
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@Transactional
@ContextConfiguration(classes = { SecurityWithoutCsrfConfig.class, PersistenceConfig.class, WebConfig.class })
@ContextConfiguration(classes = { SecurityWithoutCsrfConfig.class, MvcConfig.class })
@WithMockUser(username = "admin", roles = { "USER", "ADMIN" })
public class SessionTimerInterceptorIntegrationTest {
@ -47,9 +44,14 @@ public class SessionTimerInterceptorIntegrationTest {
*/
@Test
public void testInterceptors() throws Exception {
HttpSession session = mockMvc.perform(get("/auth/admin")).andExpect(status().is2xxSuccessful()).andReturn().getRequest().getSession();
HttpSession session = mockMvc.perform(get("/auth/foos"))
.andExpect(status().is2xxSuccessful())
.andReturn()
.getRequest()
.getSession();
Thread.sleep(51000);
mockMvc.perform(get("/auth/admin").session((MockHttpSession) session)).andExpect(status().is2xxSuccessful());
mockMvc.perform(get("/auth/foos").session((MockHttpSession) session))
.andExpect(status().is2xxSuccessful());
}
}

View File

@ -1,8 +1,10 @@
package org.baeldung.web.interceptor;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.baeldung.security.spring.SecurityWithoutCsrfConfig;
import org.baeldung.spring.PersistenceConfig;
import org.baeldung.spring.WebConfig;
import org.baeldung.spring.MvcConfig;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -14,16 +16,11 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@Transactional
@ContextConfiguration(classes = { SecurityWithoutCsrfConfig.class, PersistenceConfig.class, WebConfig.class })
@ContextConfiguration(classes = { SecurityWithoutCsrfConfig.class, MvcConfig.class })
@WithMockUser(username = "admin", roles = { "USER", "ADMIN" })
public class UserInterceptorIntegrationTest {
@ -46,7 +43,8 @@ public class UserInterceptorIntegrationTest {
*/
@Test
public void testInterceptors() throws Exception {
mockMvc.perform(get("/auth/admin")).andExpect(status().is2xxSuccessful());
mockMvc.perform(get("/auth/foos"))
.andExpect(status().is2xxSuccessful());
}
}

View File

@ -1,18 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<beansProjectDescription>
<version>1</version>
<pluginVersion><![CDATA[3.8.2.201610040608-RELEASE]]></pluginVersion>
<pluginVersion><![CDATA[3.6.3.201411271034-RELEASE]]></pluginVersion>
<configSuffixes>
<configSuffix><![CDATA[xml]]></configSuffix>
</configSuffixes>
<enableImports><![CDATA[false]]></enableImports>
<configs>
<config>java:org.baeldung.security.spring.SecurityWithoutCsrfConfig</config>
</configs>
<autoconfigs>
<config>src/main/webapp/WEB-INF/api-servlet.xml</config>
<config>java:org.baeldung.spring.Application</config>
<config>java:org.baeldung.security.spring.SecurityWithCsrfConfig</config>
</autoconfigs>
<configSets>
</configSets>

View File

@ -8,12 +8,10 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
The "Learn Spring Security" Classes: http://github.learnspringsecurity.com
### Relevant Articles:
- [Spring Security Expressions - hasRole Example](http://www.baeldung.com/spring-security-expressions-basic)
- [REST Pagination in Spring](http://www.baeldung.com/2012/01/18/rest-pagination-in-spring/)
- [HATEOAS for a Spring REST Service](http://www.baeldung.com/2011/11/13/rest-service-discoverability-with-spring-part-5/)
- [REST API Discoverability and HATEOAS](http://www.baeldung.com/2011/11/06/restful-web-service-discoverability-part-4/)
- [ETags for REST with Spring](http://www.baeldung.com/2013/01/11/etags-for-rest-with-spring/)
- [Error Handling for REST with Spring 3](http://www.baeldung.com/2013/01/31/exception-handling-for-rest-with-spring-3-2/)
- [Integration Testing with the Maven Cargo plugin](http://www.baeldung.com/2011/10/16/how-to-set-up-integration-testing-with-the-maven-cargo-plugin/)
- [Introduction to Spring Data JPA](http://www.baeldung.com/2011/12/22/the-persistence-layer-with-spring-data-jpa/)
- [Project Configuration with Spring](http://www.baeldung.com/2012/03/12/project-configuration-with-spring/)
@ -24,11 +22,6 @@ The "Learn Spring Security" Classes: http://github.learnspringsecurity.com
- [Metrics for your Spring REST API](http://www.baeldung.com/spring-rest-api-metrics)
- [REST Query Language with RSQL](http://www.baeldung.com/rest-api-search-language-rsql-fiql)
- [Spring RestTemplate Tutorial](http://www.baeldung.com/rest-template)
- [A Guide to CSRF Protection in Spring Security](http://www.baeldung.com/spring-security-csrf)
- [Intro to Spring Security Expressions](http://www.baeldung.com/spring-security-expressions)
- [Changing Spring Model Parameters with Handler Interceptor](http://www.baeldung.com/spring-model-parameters-with-handler-interceptor)
- [Introduction to Spring MVC HandlerInterceptor](http://www.baeldung.com/spring-mvc-handlerinterceptor)
- [Using a Custom Spring MVCs Handler Interceptor to Manage Sessions](http://www.baeldung.com/spring-mvc-custom-handler-interceptor)
- [Bootstrap a Web Application with Spring 4](http://www.baeldung.com/bootstraping-a-web-application-with-spring-and-java-based-configuration)
- [REST Query Language Implementing OR Operation](http://www.baeldung.com/rest-api-query-search-or-operation)

View File

@ -38,17 +38,6 @@
<scope>provided</scope>
</dependency>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
<!-- Spring -->
<dependency>
@ -220,10 +209,6 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
</dependency>
<!-- <dependency> -->
<!-- <groupId>org.hamcrest</groupId> -->

View File

@ -10,7 +10,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -36,6 +35,7 @@ public class FooService extends AbstractService<Foo> implements IFooService {
// custom methods
@Override
public Foo retrieveByName(final String name) {
return dao.retrieveByName(name);
}
@ -44,7 +44,6 @@ public class FooService extends AbstractService<Foo> implements IFooService {
@Override
@Transactional(readOnly = true)
@PreAuthorize("hasRole('ROLE_ADMIN')")
public List<Foo> findAll() {
return Lists.newArrayList(getDao().findAll());
}

View File

@ -1,14 +1,10 @@
package org.baeldung.spring;
import org.baeldung.web.interceptor.LoggerInterceptor;
import org.baeldung.web.interceptor.SessionTimerInterceptor;
import org.baeldung.web.interceptor.UserInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@ -35,15 +31,7 @@ public class WebConfig extends WebMvcConfigurerAdapter {
public void addViewControllers(final ViewControllerRegistry registry) {
super.addViewControllers(registry);
registry.addViewController("/graph.html");
registry.addViewController("/csrfHome.html");
registry.addViewController("/homepage.html");
}
@Override
public void addInterceptors(final InterceptorRegistry registry) {
registry.addInterceptor(new LoggerInterceptor());
registry.addInterceptor(new UserInterceptor());
registry.addInterceptor(new SessionTimerInterceptor());
}
}

View File

@ -11,7 +11,6 @@ import org.baeldung.web.metric.IMetricService;
import org.baeldung.web.util.LinkUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@ -53,7 +52,6 @@ public class RootController {
return metricService.getFullMetric();
}
@PreAuthorize("hasRole('ROLE_ADMIN')")
@RequestMapping(value = "/status-metric", method = RequestMethod.GET)
@ResponseBody
public Map getStatusMetric() {
@ -70,16 +68,5 @@ public class RootController {
return result;
}
@RequestMapping(value = "/admin/x", method = RequestMethod.GET)
@ResponseBody
public String sampleAdminPage() {
return "Hello";
}
@RequestMapping(value = "/my-error-page", method = RequestMethod.GET)
@ResponseBody
public String sampleErrorPage() {
return "Error Occurred";
}
}

View File

@ -11,13 +11,11 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
//import org.springframework.security.access.AccessDeniedException;
@ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
@ -55,12 +53,6 @@ public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionH
return handleExceptionInternal(ex, bodyOfResponse, headers, HttpStatus.BAD_REQUEST, request);
}
// 403
@ExceptionHandler({ AccessDeniedException.class })
public ResponseEntity<Object> handleAccessDeniedException(final Exception ex, final WebRequest request) {
System.out.println("request" + request.getUserPrincipal());
return new ResponseEntity<Object>("Access denied message here", new HttpHeaders(), HttpStatus.FORBIDDEN);
}
// 404

View File

@ -1,40 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
xsi:schemaLocation="
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
>
<http pattern="/securityNone" security="none"/>
<http use-expressions="true" >
<intercept-url pattern="/admin/*" access="hasAnyRole('ROLE_ADMIN')"/>
<intercept-url pattern="/**" access="isAuthenticated()"/>
<http-basic/>
<csrf disabled="true"/>
<!-- <access-denied-handler error-page="/my-error-page" /> -->
<access-denied-handler ref="customAccessDeniedHandler" />
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="user1" password="user1Pass" authorities="ROLE_USER"/>
<user name="admin" password="adminPass" authorities="ROLE_ADMIN"/>
</user-service>
</authentication-provider>
</authentication-manager>
<global-method-security pre-post-annotations="enabled"/>
<!-- <mvc:interceptors>
<bean id="loggerInterceptor" class="org.baeldung.web.interceptor.LoggerInterceptor" />
</mvc:interceptors> -->
</beans:beans>

View File

@ -1,7 +1,6 @@
package org.baeldung;
import org.baeldung.persistence.PersistenceTestSuite;
import org.baeldung.security.SecurityTestSuite;
import org.baeldung.web.LiveTestSuite;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@ -10,7 +9,6 @@ import org.junit.runners.Suite;
@Suite.SuiteClasses({
// @formatter:off
PersistenceTestSuite.class
,SecurityTestSuite.class
,LiveTestSuite.class
}) //
public class TestSuite {

View File

@ -1,16 +0,0 @@
package org.baeldung.security;
import org.baeldung.security.csrf.CsrfDisabledIntegrationTest;
import org.baeldung.security.csrf.CsrfEnabledIntegrationTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@RunWith(Suite.class)
@Suite.SuiteClasses({
// @formatter:off
CsrfEnabledIntegrationTest.class
,CsrfDisabledIntegrationTest.class
}) //
public class SecurityTestSuite {
}

View File

@ -1,44 +0,0 @@
package org.baeldung.security.csrf;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.baeldung.security.spring.SecurityWithoutCsrfConfig;
import org.baeldung.spring.PersistenceConfig;
import org.baeldung.spring.WebConfig;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
@ContextConfiguration(classes = { SecurityWithoutCsrfConfig.class, PersistenceConfig.class, WebConfig.class })
public class CsrfDisabledIntegrationTest extends CsrfAbstractIntegrationTest {
@Test
public void givenNotAuth_whenAddFoo_thenUnauthorized() throws Exception {
mvc.perform(post("/auth/foos").contentType(MediaType.APPLICATION_JSON).content(createFoo())).andExpect(status().isUnauthorized());
}
@Test
public void givenAuth_whenAddFoo_thenCreated() throws Exception {
mvc.perform(post("/auth/foos").contentType(MediaType.APPLICATION_JSON).content(createFoo()).with(testUser())).andExpect(status().isCreated());
}
@Test
public void accessMainPageWithoutAuthorization() throws Exception {
mvc.perform(get("/graph.html").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk());
}
@Test
public void accessOtherPages() throws Exception {
mvc.perform(get("/auth/transfer").contentType(MediaType.APPLICATION_JSON).param("accountNo", "1").param("amount", "100")).andExpect(status().isUnauthorized()); // without authorization
mvc.perform(get("/auth/transfer").contentType(MediaType.APPLICATION_JSON).param("accountNo", "1").param("amount", "100").with(testUser())).andExpect(status().isOk()); // with authorization
}
@Test
public void accessAdminPage() throws Exception {
mvc.perform(get("/auth/admin/x").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isUnauthorized()); // without authorization
mvc.perform(get("/auth/admin/x").contentType(MediaType.APPLICATION_JSON).with(testAdmin())).andExpect(status().isOk()); // with authorization
}
}

View File

@ -14,3 +14,6 @@ The "Learn Spring Security" Classes: http://github.learnspringsecurity.com
- [An Intro to Spring HATEOAS](http://www.baeldung.com/spring-hateoas-tutorial)
- [Spring Security Context Propagation with @Async](http://www.baeldung.com/spring-security-async-principal-propagation)
- [Servlet 3 Async Support with Spring MVC and Spring Security](http://www.baeldung.com/spring-mvc-async-security)
- [Intro to Spring Security Expressions](http://www.baeldung.com/spring-security-expressions)
- [Spring Security Expressions - hasRole Example](http://www.baeldung.com/spring-security-expressions-basic)
- [Error Handling for REST with Spring 3](http://www.baeldung.com/2013/01/31/exception-handling-for-rest-with-spring-3-2/)

View File

@ -1,10 +1,13 @@
package org.baeldung.spring;
import org.baeldung.security.MySavedRequestAwareAuthenticationSuccessHandler;
import org.baeldung.web.error.CustomAccessDeniedHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@ -13,9 +16,13 @@ import org.springframework.security.web.authentication.SimpleUrlAuthenticationFa
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@ComponentScan("org.baeldung.security")
public class SecurityJavaConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomAccessDeniedHandler accessDeniedHandler;
// @Autowired
// private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
@ -40,7 +47,7 @@ public class SecurityJavaConfig extends WebSecurityConfigurerAdapter {
.csrf().disable()
.authorizeRequests()
.and()
.exceptionHandling()
.exceptionHandling().accessDeniedHandler(accessDeniedHandler)
// .authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.authorizeRequests()
@ -48,6 +55,7 @@ public class SecurityJavaConfig extends WebSecurityConfigurerAdapter {
.antMatchers("/api/customer/**").permitAll()
.antMatchers("/api/foos/**").authenticated()
.antMatchers("/api/async/**").permitAll()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.and()
.httpBasic()
// .and()

View File

@ -1,19 +1,23 @@
package org.baeldung.spring;
import static com.google.common.collect.Lists.newArrayList;
import java.util.Collections;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RequestMethod;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.builders.ResponseMessageBuilder;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import static com.google.common.collect.Lists.newArrayList;
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@ -25,7 +29,7 @@ public class SwaggerConfig {
}
private ApiInfo apiInfo() {
ApiInfo apiInfo = new ApiInfo("My REST API", "Some custom description of API.", "API TOS", "Terms of service", "myeaddress@company.com", "License of API", "API license URL");
ApiInfo apiInfo = new ApiInfo("My REST API", "Some custom description of API.", "API TOS", "Terms of service", new Contact("John Doe", "www.example.com", "myeaddress@company.com"), "License of API", "API license URL", Collections.emptyList());
return apiInfo;
}
}

View File

@ -0,0 +1,30 @@
package org.baeldung.web.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class RootController {
public RootController() {
super();
}
// API
@RequestMapping(value = "/admin/x", method = RequestMethod.GET)
@ResponseBody
public String sampleAdminPage() {
return "Hello";
}
@RequestMapping(value = "/my-error-page", method = RequestMethod.GET)
@ResponseBody
public String sampleErrorPage() {
return "Error Occurred";
}
}

View File

@ -0,0 +1,74 @@
package org.baeldung.web.error;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
//import org.springframework.security.access.AccessDeniedException;
@ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
public RestResponseEntityExceptionHandler() {
super();
}
// API
// 400
@ExceptionHandler({ DataIntegrityViolationException.class })
public ResponseEntity<Object> handleBadRequest(final DataIntegrityViolationException ex, final WebRequest request) {
final String bodyOfResponse = "This should be application specific";
return handleExceptionInternal(ex, bodyOfResponse, new HttpHeaders(), HttpStatus.BAD_REQUEST, request);
}
@Override
protected ResponseEntity<Object> handleHttpMessageNotReadable(final HttpMessageNotReadableException ex, final HttpHeaders headers, final HttpStatus status, final WebRequest request) {
final String bodyOfResponse = "This should be application specific";
// ex.getCause() instanceof JsonMappingException, JsonParseException // for additional information later on
return handleExceptionInternal(ex, bodyOfResponse, headers, HttpStatus.BAD_REQUEST, request);
}
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(final MethodArgumentNotValidException ex, final HttpHeaders headers, final HttpStatus status, final WebRequest request) {
final String bodyOfResponse = "This should be application specific";
return handleExceptionInternal(ex, bodyOfResponse, headers, HttpStatus.BAD_REQUEST, request);
}
// 403
@ExceptionHandler({ AccessDeniedException.class })
public ResponseEntity<Object> handleAccessDeniedException(final Exception ex, final WebRequest request) {
System.out.println("request" + request.getUserPrincipal());
return new ResponseEntity<Object>("Access denied message here", new HttpHeaders(), HttpStatus.FORBIDDEN);
}
// 409
@ExceptionHandler({ InvalidDataAccessApiUsageException.class, DataAccessException.class })
protected ResponseEntity<Object> handleConflict(final RuntimeException ex, final WebRequest request) {
final String bodyOfResponse = "This should be application specific";
return handleExceptionInternal(ex, bodyOfResponse, new HttpHeaders(), HttpStatus.CONFLICT, request);
}
// 412
// 500
@ExceptionHandler({ NullPointerException.class, IllegalArgumentException.class, IllegalStateException.class })
/*500*/public ResponseEntity<Object> handleInternal(final RuntimeException ex, final WebRequest request) {
logger.error("500 Status Code", ex);
final String bodyOfResponse = "This should be application specific";
return handleExceptionInternal(ex, bodyOfResponse, new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR, request);
}
}

View File

@ -0,0 +1,21 @@
package org.baeldung.web.exception;
public final class MyResourceNotFoundException extends RuntimeException {
public MyResourceNotFoundException() {
super();
}
public MyResourceNotFoundException(final String message, final Throwable cause) {
super(message, cause);
}
public MyResourceNotFoundException(final String message) {
super(message);
}
public MyResourceNotFoundException(final Throwable cause) {
super(cause);
}
}

View File

@ -10,6 +10,8 @@
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd">
<http use-expressions="true" entry-point-ref="restAuthenticationEntryPoint">
<intercept-url pattern="/admin/*" access="hasAnyRole('ROLE_ADMIN')"/>
<intercept-url pattern="/api/**" access="isAuthenticated()" />
<csrf disabled="true" />
@ -17,6 +19,11 @@
<form-login authentication-success-handler-ref="mySuccessHandler"
authentication-failure-handler-ref="myFailureHandler" />
<!-- <access-denied-handler error-page="/my-error-page" /> -->
<access-denied-handler ref="customAccessDeniedHandler" />
<logout />
</http>
@ -30,8 +37,12 @@
<user-service>
<user name="temporary" password="temporary" authorities="ROLE_ADMIN" />
<user name="user" password="userPass" authorities="ROLE_USER" />
<user name="user1" password="user1Pass" authorities="ROLE_USER"/>
<user name="admin" password="adminPass" authorities="ROLE_ADMIN"/>
</user-service>
</authentication-provider>
</authentication-manager>
<global-method-security pre-post-annotations="enabled"/>
</beans:beans>

View File

@ -17,17 +17,20 @@ import com.jayway.restassured.specification.RequestSpecification;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { TestConfig.class }, loader = AnnotationConfigContextLoader.class)
public class FooLiveTest {
private static final String URL_PREFIX = "http://localhost:8082/spring-security-rest";
private static final String URL_PREFIX = "http://localhost:8080/spring-security-rest";
// private FormAuthConfig formConfig = new FormAuthConfig(URL_PREFIX + "/login", "temporary", "temporary");
private String cookie;
private RequestSpecification givenAuth() {
// return RestAssured.given().auth().form("user", "userPass", formConfig);
if (cookie == null) {
cookie = RestAssured.given().contentType("application/x-www-form-urlencoded").formParam("password", "userPass").formParam("username", "user").post(URL_PREFIX + "/login").getCookie("JSESSIONID");
}
return RestAssured.given().cookie("JSESSIONID", cookie);
// if (cookie == null) {
// cookie = RestAssured.given().contentType("application/x-www-form-urlencoded").formParam("password", "userPass").formParam("username", "user").post(URL_PREFIX + "/login").getCookie("JSESSIONID");
// }
// return RestAssured.given().cookie("JSESSIONID", cookie);
return RestAssured.given()
.auth()
.basic("user", "userPass");
}
@Test

View File

@ -8,7 +8,7 @@ import com.jayway.restassured.RestAssured;
import com.jayway.restassured.response.Response;
public class SwaggerLiveTest {
private static final String URL_PREFIX = "http://localhost:8082/spring-security-rest/api";
private static final String URL_PREFIX = "http://localhost:8080/spring-security-rest/api";
@Test
public void whenVerifySpringFoxIsWorking_thenOK() {

View File

@ -1 +1,3 @@
## Relevant articles:
- [Introduction to Vaadin](http://www.baeldung.com/vaadin)