Merge branch 'master' into cxf-spring
This commit is contained in:
commit
d4a45164f6
|
@ -29,7 +29,7 @@
|
||||||
</classpathentry>
|
</classpathentry>
|
||||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
|
||||||
<attributes>
|
<attributes>
|
||||||
<attribute name="owner.project.facets" value="java"/>
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
</attributes>
|
</attributes>
|
||||||
</classpathentry>
|
</classpathentry>
|
||||||
<classpathentry kind="output" path="target/classes"/>
|
<classpathentry kind="output" path="target/classes"/>
|
||||||
|
|
|
@ -109,6 +109,31 @@
|
||||||
<version>${mockito.version}</version>
|
<version>${mockito.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- logging -->
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
<version>${org.slf4j.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
<version>${logback.version}</version>
|
||||||
|
<!-- <scope>runtime</scope> -->
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>jcl-over-slf4j</artifactId>
|
||||||
|
<version>${org.slf4j.version}</version>
|
||||||
|
<!-- <scope>runtime</scope> --> <!-- some spring dependencies need to compile against jcl -->
|
||||||
|
</dependency>
|
||||||
|
<dependency> <!-- needed to bridge to slf4j for projects that use the log4j APIs directly -->
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>log4j-over-slf4j</artifactId>
|
||||||
|
<version>${org.slf4j.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
package com.baeldung.jackson.objectmapper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.baeldung.jackson.objectmapper.dto.Car;
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.core.ObjectCodec;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||||
|
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
|
||||||
|
public class CustomCarDeserializer extends JsonDeserializer<Car> {
|
||||||
|
private final Logger Logger = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
|
public CustomCarDeserializer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Car deserialize(final JsonParser parser, final DeserializationContext deserializer) throws IOException {
|
||||||
|
final Car car = new Car();
|
||||||
|
final ObjectCodec codec = parser.getCodec();
|
||||||
|
final JsonNode node = codec.readTree(parser);
|
||||||
|
try {
|
||||||
|
final JsonNode colorNode = node.get("color");
|
||||||
|
final String color = colorNode.asText();
|
||||||
|
car.setColor(color);
|
||||||
|
} catch (final Exception e) {
|
||||||
|
Logger.debug("101_parse_exeption: unknown json.");
|
||||||
|
}
|
||||||
|
return car;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.baeldung.jackson.objectmapper;
|
||||||
|
|
||||||
|
import com.baeldung.jackson.objectmapper.dto.Car;
|
||||||
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||||
|
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class CustomCarSerializer extends JsonSerializer<Car>
|
||||||
|
{
|
||||||
|
public CustomCarSerializer() { }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void serialize(final Car car, final JsonGenerator jsonGenerator, final SerializerProvider serializer) throws IOException, JsonProcessingException
|
||||||
|
{
|
||||||
|
jsonGenerator.writeStartObject();
|
||||||
|
jsonGenerator.writeStringField("model: ", car.getType());
|
||||||
|
jsonGenerator.writeEndObject();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
package com.baeldung.jackson.objectmapper;
|
||||||
|
|
||||||
|
import com.baeldung.jackson.objectmapper.dto.Car;
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
public class TestJavaReadWriteJsonExample {
|
||||||
|
final String EXAMPLE_JSON = "{ \"color\" : \"Black\", \"type\" : \"BMW\" }";
|
||||||
|
final String LOCAL_JSON = "[{ \"color\" : \"Black\", \"type\" : \"BMW\" }, { \"color\" : \"Red\", \"type\" : \"BMW\" }]";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenWriteJavaToJson_thanCorrect() throws Exception {
|
||||||
|
final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
final Car car = new Car("yellow", "renault");
|
||||||
|
final String carAsString = objectMapper.writeValueAsString(car);
|
||||||
|
assertThat(carAsString, containsString("yellow"));
|
||||||
|
assertThat(carAsString, containsString("renault"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenReadJsonToJava_thanCorrect() throws Exception {
|
||||||
|
final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
final Car car = objectMapper.readValue(EXAMPLE_JSON, Car.class);
|
||||||
|
assertNotNull(car);
|
||||||
|
assertThat(car.getColor(), containsString("Black"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenReadJsonToJsonNode_thanCorrect() throws Exception {
|
||||||
|
final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
final JsonNode jsonNode = objectMapper.readTree(EXAMPLE_JSON);
|
||||||
|
assertNotNull(jsonNode);
|
||||||
|
assertThat(jsonNode.get("color").asText(), containsString("Black"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenReadJsonToList_thanCorrect() throws Exception {
|
||||||
|
final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
final List<Car> listCar = objectMapper.readValue(LOCAL_JSON, new TypeReference<List<Car>>() {
|
||||||
|
|
||||||
|
});
|
||||||
|
for (final Car car : listCar) {
|
||||||
|
assertNotNull(car);
|
||||||
|
assertThat(car.getType(), equalTo("BMW"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenReadJsonToMap_thanCorrect() throws Exception {
|
||||||
|
final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
final Map<String, Object> map = objectMapper.readValue(EXAMPLE_JSON, new TypeReference<Map<String, Object>>() {
|
||||||
|
});
|
||||||
|
assertNotNull(map);
|
||||||
|
for (final String key : map.keySet()) {
|
||||||
|
assertNotNull(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
package com.baeldung.jackson.objectmapper;
|
||||||
|
|
||||||
|
import com.baeldung.jackson.objectmapper.dto.Car;
|
||||||
|
import com.baeldung.jackson.objectmapper.dto.Request;
|
||||||
|
import com.fasterxml.jackson.core.Version;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
public class TestSerializationDeserializationFeature {
|
||||||
|
final String EXAMPLE_JSON = "{ \"color\" : \"Black\", \"type\" : \"BMW\" }";
|
||||||
|
final String JSON_CAR = "{ \"color\" : \"Black\", \"type\" : \"Fiat\", \"year\" : \"1970\" }";
|
||||||
|
final String JSON_ARRAY = "[{ \"color\" : \"Black\", \"type\" : \"BMW\" }, { \"color\" : \"Red\", \"type\" : \"BMW\" }]";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenFailOnUnkownPropertiesFalse_thanJsonReadCorrectly() throws Exception {
|
||||||
|
|
||||||
|
final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||||
|
final Car car = objectMapper.readValue(JSON_CAR, Car.class);
|
||||||
|
final JsonNode jsonNodeRoot = objectMapper.readTree(JSON_CAR);
|
||||||
|
final JsonNode jsonNodeYear = jsonNodeRoot.get("year");
|
||||||
|
final String year = jsonNodeYear.asText();
|
||||||
|
|
||||||
|
assertNotNull(car);
|
||||||
|
assertThat(car.getColor(), equalTo("Black"));
|
||||||
|
assertThat(year, containsString("1970"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenCustomSerializerDeserializer_thanReadWriteCorrect() throws Exception {
|
||||||
|
final ObjectMapper mapper = new ObjectMapper();
|
||||||
|
final SimpleModule serializerModule = new SimpleModule("CustomSerializer", new Version(1, 0, 0, null, null, null));
|
||||||
|
serializerModule.addSerializer(Car.class, new CustomCarSerializer());
|
||||||
|
mapper.registerModule(serializerModule);
|
||||||
|
final Car car = new Car("yellow", "renault");
|
||||||
|
final String carJson = mapper.writeValueAsString(car);
|
||||||
|
assertThat(carJson, containsString("renault"));
|
||||||
|
assertThat(carJson, containsString("model"));
|
||||||
|
|
||||||
|
final SimpleModule deserializerModule = new SimpleModule("CustomCarDeserializer", new Version(1, 0, 0, null, null, null));
|
||||||
|
deserializerModule.addDeserializer(Car.class, new CustomCarDeserializer());
|
||||||
|
mapper.registerModule(deserializerModule);
|
||||||
|
final Car carResult = mapper.readValue(EXAMPLE_JSON, Car.class);
|
||||||
|
assertNotNull(carResult);
|
||||||
|
assertThat(carResult.getColor(), equalTo("Black"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenDateFormatSet_thanSerializedAsExpected() throws Exception {
|
||||||
|
final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
final Car car = new Car("yellow", "renault");
|
||||||
|
final Request request = new Request();
|
||||||
|
request.setCar(car);
|
||||||
|
request.setDatePurchased(new Date());
|
||||||
|
final DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm a z");
|
||||||
|
objectMapper.setDateFormat(df);
|
||||||
|
final String carAsString = objectMapper.writeValueAsString(request);
|
||||||
|
assertNotNull(carAsString);
|
||||||
|
assertThat(carAsString, containsString("datePurchased"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenUseJavaArrayForJsonArrayTrue_thanJsonReadAsArray() throws Exception {
|
||||||
|
final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
objectMapper.configure(DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY, true);
|
||||||
|
final Car[] cars = objectMapper.readValue(JSON_ARRAY, Car[].class);
|
||||||
|
for (final Car car : cars) {
|
||||||
|
assertNotNull(car);
|
||||||
|
assertThat(car.getType(), equalTo("BMW"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package com.baeldung.jackson.objectmapper.dto;
|
||||||
|
|
||||||
|
public class Car {
|
||||||
|
|
||||||
|
private String color;
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
public Car() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Car(final String color, final String type) {
|
||||||
|
this.color = color;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getColor() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor(final String color) {
|
||||||
|
this.color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(final String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.baeldung.jackson.objectmapper.dto;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class Request {
|
||||||
|
Car car;
|
||||||
|
Date datePurchased;
|
||||||
|
|
||||||
|
public Car getCar() {
|
||||||
|
return car;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCar(final Car car) {
|
||||||
|
this.car = car;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getDatePurchased() {
|
||||||
|
return datePurchased;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDatePurchased(final Date datePurchased) {
|
||||||
|
this.datePurchased = datePurchased;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
.idea
|
||||||
|
target
|
||||||
|
*.iml
|
|
@ -0,0 +1,45 @@
|
||||||
|
## JWT Fun
|
||||||
|
|
||||||
|
This tutorial walks you through the various features supported by the [JJWT](https://github.com/jwtk/jjwt) library - a fluent interface Java JWT building and parsing library.
|
||||||
|
|
||||||
|
### Build and Run
|
||||||
|
|
||||||
|
It's super easy to build and exercise this tutorial.
|
||||||
|
|
||||||
|
```
|
||||||
|
mvn clean install
|
||||||
|
java -jar target/*.jar
|
||||||
|
```
|
||||||
|
|
||||||
|
That's it!
|
||||||
|
|
||||||
|
You can hit the home endpoint with your favorite command-line http client. My favorite is: [httpie](https://github.com/jkbrzt/httpie)
|
||||||
|
|
||||||
|
`http localhost:8080`
|
||||||
|
|
||||||
|
```
|
||||||
|
Available commands (assumes httpie - https://github.com/jkbrzt/httpie):
|
||||||
|
|
||||||
|
http http://localhost:8080/
|
||||||
|
This usage message
|
||||||
|
|
||||||
|
http http://localhost:8080/static-builder
|
||||||
|
build JWT from hardcoded claims
|
||||||
|
|
||||||
|
http POST http://localhost:8080/dynamic-builder-general claim-1=value-1 ... [claim-n=value-n]
|
||||||
|
build JWT from passed in claims (using general claims map)
|
||||||
|
|
||||||
|
http POST http://localhost:8080/dynamic-builder-specific claim-1=value-1 ... [claim-n=value-n]
|
||||||
|
build JWT from passed in claims (using specific claims methods)
|
||||||
|
|
||||||
|
http POST http://localhost:8080/dynamic-builder-compress claim-1=value-1 ... [claim-n=value-n]
|
||||||
|
build DEFLATE compressed JWT from passed in claims
|
||||||
|
|
||||||
|
http http://localhost:8080/parser?jwt=<jwt>
|
||||||
|
Parse passed in JWT
|
||||||
|
|
||||||
|
http http://localhost:8080/parser-enforce?jwt=<jwt>
|
||||||
|
Parse passed in JWT enforcing the 'iss' registered claim and the 'hasMotorcycle' custom claim
|
||||||
|
```
|
||||||
|
|
||||||
|
The Baeldung post that compliments this repo can be found [here](http://www.baeldung.com/)
|
|
@ -0,0 +1,65 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<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>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwtfun</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>jjwtfun</name>
|
||||||
|
<description>Exercising the JJWT</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>1.3.5.RELEASE</version>
|
||||||
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<java.version>1.8</java.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-devtools</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-security</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt</artifactId>
|
||||||
|
<version>0.6.0</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,12 @@
|
||||||
|
package io.jsonwebtoken.jjwtfun;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class JJWTFunApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(JJWTFunApplication.class, args);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package io.jsonwebtoken.jjwtfun.config;
|
||||||
|
|
||||||
|
import io.jsonwebtoken.jjwtfun.service.SecretService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.web.csrf.CsrfTokenRepository;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class CSRFConfig {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
SecretService secretService;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public CsrfTokenRepository jwtCsrfTokenRepository() {
|
||||||
|
return new JWTCsrfTokenRepository(secretService.getHS256SecretBytes());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
package io.jsonwebtoken.jjwtfun.config;
|
||||||
|
|
||||||
|
import io.jsonwebtoken.Jwts;
|
||||||
|
import io.jsonwebtoken.SignatureAlgorithm;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.security.web.csrf.CsrfToken;
|
||||||
|
import org.springframework.security.web.csrf.CsrfTokenRepository;
|
||||||
|
import org.springframework.security.web.csrf.DefaultCsrfToken;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import javax.servlet.http.HttpSession;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class JWTCsrfTokenRepository implements CsrfTokenRepository {
|
||||||
|
|
||||||
|
private static final String DEFAULT_CSRF_TOKEN_ATTR_NAME = CSRFConfig.class.getName().concat(".CSRF_TOKEN");
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(JWTCsrfTokenRepository.class);
|
||||||
|
private byte[] secret;
|
||||||
|
|
||||||
|
public JWTCsrfTokenRepository(byte[] secret) {
|
||||||
|
this.secret = secret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CsrfToken generateToken(HttpServletRequest request) {
|
||||||
|
String id = UUID.randomUUID().toString().replace("-", "");
|
||||||
|
|
||||||
|
Date now = new Date();
|
||||||
|
Date exp = new Date(System.currentTimeMillis() + (1000*30)); // 30 seconds
|
||||||
|
|
||||||
|
String token = Jwts.builder()
|
||||||
|
.setId(id)
|
||||||
|
.setIssuedAt(now)
|
||||||
|
.setNotBefore(now)
|
||||||
|
.setExpiration(exp)
|
||||||
|
.signWith(SignatureAlgorithm.HS256, secret)
|
||||||
|
.compact();
|
||||||
|
|
||||||
|
return new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", token);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveToken(CsrfToken token, HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
if (token == null) {
|
||||||
|
HttpSession session = request.getSession(false);
|
||||||
|
if (session != null) {
|
||||||
|
session.removeAttribute(DEFAULT_CSRF_TOKEN_ATTR_NAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
HttpSession session = request.getSession();
|
||||||
|
session.setAttribute(DEFAULT_CSRF_TOKEN_ATTR_NAME, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CsrfToken loadToken(HttpServletRequest request) {
|
||||||
|
HttpSession session = request.getSession(false);
|
||||||
|
if (session == null || "GET".equals(request.getMethod())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (CsrfToken) session.getAttribute(DEFAULT_CSRF_TOKEN_ATTR_NAME);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
package io.jsonwebtoken.jjwtfun.config;
|
||||||
|
|
||||||
|
import io.jsonwebtoken.JwtException;
|
||||||
|
import io.jsonwebtoken.Jwts;
|
||||||
|
import io.jsonwebtoken.jjwtfun.service.SecretService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||||
|
import org.springframework.security.web.csrf.CsrfFilter;
|
||||||
|
import org.springframework.security.web.csrf.CsrfToken;
|
||||||
|
import org.springframework.security.web.csrf.CsrfTokenRepository;
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.RequestDispatcher;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
CsrfTokenRepository jwtCsrfTokenRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
SecretService secretService;
|
||||||
|
|
||||||
|
// ordered so we can use binary search below
|
||||||
|
private String[] ignoreCsrfAntMatchers = {
|
||||||
|
"/dynamic-builder-compress",
|
||||||
|
"/dynamic-builder-general",
|
||||||
|
"/dynamic-builder-specific",
|
||||||
|
"/set-secrets"
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
|
http
|
||||||
|
.addFilterAfter(new JwtCsrfValidatorFilter(), CsrfFilter.class)
|
||||||
|
.csrf()
|
||||||
|
.csrfTokenRepository(jwtCsrfTokenRepository)
|
||||||
|
.ignoringAntMatchers(ignoreCsrfAntMatchers)
|
||||||
|
.and().authorizeRequests()
|
||||||
|
.antMatchers("/**")
|
||||||
|
.permitAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class JwtCsrfValidatorFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||||
|
// NOTE: A real implementation should have a nonce cache so the token cannot be reused
|
||||||
|
|
||||||
|
CsrfToken token = (CsrfToken) request.getAttribute("_csrf");
|
||||||
|
|
||||||
|
if (
|
||||||
|
// only care if it's a POST
|
||||||
|
"POST".equals(request.getMethod()) &&
|
||||||
|
// ignore if the request path is in our list
|
||||||
|
Arrays.binarySearch(ignoreCsrfAntMatchers, request.getServletPath()) < 0 &&
|
||||||
|
// make sure we have a token
|
||||||
|
token != null
|
||||||
|
) {
|
||||||
|
// CsrfFilter already made sure the token matched. Here, we'll make sure it's not expired
|
||||||
|
try {
|
||||||
|
Jwts.parser()
|
||||||
|
.setSigningKeyResolver(secretService.getSigningKeyResolver())
|
||||||
|
.parseClaimsJws(token.getToken());
|
||||||
|
} catch (JwtException e) {
|
||||||
|
// most likely an ExpiredJwtException, but this will handle any
|
||||||
|
request.setAttribute("exception", e);
|
||||||
|
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||||
|
RequestDispatcher dispatcher = request.getRequestDispatcher("expired-jwt");
|
||||||
|
dispatcher.forward(request, response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package io.jsonwebtoken.jjwtfun.controller;
|
||||||
|
|
||||||
|
import io.jsonwebtoken.JwtException;
|
||||||
|
import io.jsonwebtoken.MalformedJwtException;
|
||||||
|
import io.jsonwebtoken.SignatureException;
|
||||||
|
import io.jsonwebtoken.jjwtfun.model.JwtResponse;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
|
||||||
|
public class BaseController {
|
||||||
|
|
||||||
|
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||||
|
@ExceptionHandler({SignatureException.class, MalformedJwtException.class, JwtException.class})
|
||||||
|
public JwtResponse exception(Exception e) {
|
||||||
|
JwtResponse response = new JwtResponse();
|
||||||
|
response.setStatus(JwtResponse.Status.ERROR);
|
||||||
|
response.setMessage(e.getMessage());
|
||||||
|
response.setExceptionType(e.getClass().getName());
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
package io.jsonwebtoken.jjwtfun.controller;
|
||||||
|
|
||||||
|
import io.jsonwebtoken.JwtBuilder;
|
||||||
|
import io.jsonwebtoken.JwtException;
|
||||||
|
import io.jsonwebtoken.Jwts;
|
||||||
|
import io.jsonwebtoken.SignatureAlgorithm;
|
||||||
|
import io.jsonwebtoken.impl.compression.CompressionCodecs;
|
||||||
|
import io.jsonwebtoken.jjwtfun.model.JwtResponse;
|
||||||
|
import io.jsonwebtoken.jjwtfun.service.SecretService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.springframework.web.bind.annotation.RequestMethod.POST;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class DynamicJWTController extends BaseController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
SecretService secretService;
|
||||||
|
|
||||||
|
@RequestMapping(value = "/dynamic-builder-general", method = POST)
|
||||||
|
public JwtResponse dynamicBuilderGeneric(@RequestBody Map<String, Object> claims) throws UnsupportedEncodingException {
|
||||||
|
String jws = Jwts.builder()
|
||||||
|
.setClaims(claims)
|
||||||
|
.signWith(
|
||||||
|
SignatureAlgorithm.HS256,
|
||||||
|
secretService.getHS256SecretBytes()
|
||||||
|
)
|
||||||
|
.compact();
|
||||||
|
return new JwtResponse(jws);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(value = "/dynamic-builder-compress", method = POST)
|
||||||
|
public JwtResponse dynamicBuildercompress(@RequestBody Map<String, Object> claims) throws UnsupportedEncodingException {
|
||||||
|
String jws = Jwts.builder()
|
||||||
|
.setClaims(claims)
|
||||||
|
.compressWith(CompressionCodecs.DEFLATE)
|
||||||
|
.signWith(
|
||||||
|
SignatureAlgorithm.HS256,
|
||||||
|
secretService.getHS256SecretBytes()
|
||||||
|
)
|
||||||
|
.compact();
|
||||||
|
return new JwtResponse(jws);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(value = "/dynamic-builder-specific", method = POST)
|
||||||
|
public JwtResponse dynamicBuilderSpecific(@RequestBody Map<String, Object> claims) throws UnsupportedEncodingException {
|
||||||
|
JwtBuilder builder = Jwts.builder();
|
||||||
|
|
||||||
|
claims.forEach((key, value) -> {
|
||||||
|
switch (key) {
|
||||||
|
case "iss":
|
||||||
|
ensureType(key, value, String.class);
|
||||||
|
builder.setIssuer((String) value);
|
||||||
|
break;
|
||||||
|
case "sub":
|
||||||
|
ensureType(key, value, String.class);
|
||||||
|
builder.setSubject((String) value);
|
||||||
|
break;
|
||||||
|
case "aud":
|
||||||
|
ensureType(key, value, String.class);
|
||||||
|
builder.setAudience((String) value);
|
||||||
|
break;
|
||||||
|
case "exp":
|
||||||
|
ensureType(key, value, Long.class);
|
||||||
|
builder.setExpiration(Date.from(Instant.ofEpochSecond(Long.parseLong(value.toString()))));
|
||||||
|
break;
|
||||||
|
case "nbf":
|
||||||
|
ensureType(key, value, Long.class);
|
||||||
|
builder.setNotBefore(Date.from(Instant.ofEpochSecond(Long.parseLong(value.toString()))));
|
||||||
|
break;
|
||||||
|
case "iat":
|
||||||
|
ensureType(key, value, Long.class);
|
||||||
|
builder.setIssuedAt(Date.from(Instant.ofEpochSecond(Long.parseLong(value.toString()))));
|
||||||
|
break;
|
||||||
|
case "jti":
|
||||||
|
ensureType(key, value, String.class);
|
||||||
|
builder.setId((String) value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
builder.claim(key, value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.signWith(SignatureAlgorithm.HS256, secretService.getHS256SecretBytes());
|
||||||
|
|
||||||
|
return new JwtResponse(builder.compact());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureType(String registeredClaim, Object value, Class expectedType) {
|
||||||
|
boolean isCorrectType =
|
||||||
|
expectedType.isInstance(value) ||
|
||||||
|
expectedType == Long.class && value instanceof Integer;
|
||||||
|
|
||||||
|
if (!isCorrectType) {
|
||||||
|
String msg = "Expected type: " + expectedType.getCanonicalName() + " for registered claim: '" +
|
||||||
|
registeredClaim + "', but got value: " + value + " of type: " + value.getClass().getCanonicalName();
|
||||||
|
throw new JwtException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package io.jsonwebtoken.jjwtfun.controller;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
||||||
|
import static org.springframework.web.bind.annotation.RequestMethod.GET;
|
||||||
|
import static org.springframework.web.bind.annotation.RequestMethod.POST;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public class FormController {
|
||||||
|
|
||||||
|
@RequestMapping(value = "/jwt-csrf-form", method = GET)
|
||||||
|
public String csrfFormGet() {
|
||||||
|
return "jwt-csrf-form";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(value = "/jwt-csrf-form", method = POST)
|
||||||
|
public String csrfFormPost(@RequestParam(name = "_csrf") String csrf, Model model) {
|
||||||
|
model.addAttribute("csrf", csrf);
|
||||||
|
return "jwt-csrf-form-result";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping("/expired-jwt")
|
||||||
|
public String expiredJwt() {
|
||||||
|
return "expired-jwt";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package io.jsonwebtoken.jjwtfun.controller;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class HomeController {
|
||||||
|
|
||||||
|
@RequestMapping("/")
|
||||||
|
public String home(HttpServletRequest req) {
|
||||||
|
String requestUrl = getUrl(req);
|
||||||
|
return "Available commands (assumes httpie - https://github.com/jkbrzt/httpie):\n\n" +
|
||||||
|
" http " + requestUrl + "/\n\tThis usage message\n\n" +
|
||||||
|
" http " + requestUrl + "/static-builder\n\tbuild JWT from hardcoded claims\n\n" +
|
||||||
|
" http POST " + requestUrl + "/dynamic-builder-general claim-1=value-1 ... [claim-n=value-n]\n\tbuild JWT from passed in claims (using general claims map)\n\n" +
|
||||||
|
" http POST " + requestUrl + "/dynamic-builder-specific claim-1=value-1 ... [claim-n=value-n]\n\tbuild JWT from passed in claims (using specific claims methods)\n\n" +
|
||||||
|
" http POST " + requestUrl + "/dynamic-builder-compress claim-1=value-1 ... [claim-n=value-n]\n\tbuild DEFLATE compressed JWT from passed in claims\n\n" +
|
||||||
|
" http " + requestUrl + "/parser?jwt=<jwt>\n\tParse passed in JWT\n\n" +
|
||||||
|
" http " + requestUrl + "/parser-enforce?jwt=<jwt>\n\tParse passed in JWT enforcing the 'iss' registered claim and the 'hasMotorcycle' custom claim\n\n" +
|
||||||
|
" http " + requestUrl + "/get-secrets\n\tShow the signing keys currently in use.\n\n" +
|
||||||
|
" http " + requestUrl + "/refresh-secrets\n\tGenerate new signing keys and show them.\n\n" +
|
||||||
|
" http POST " + requestUrl + "/set-secrets HS256=base64-encoded-value HS384=base64-encoded-value HS512=base64-encoded-value\n\tExplicitly set secrets to use in the application.";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getUrl(HttpServletRequest req) {
|
||||||
|
return req.getScheme() + "://" +
|
||||||
|
req.getServerName() +
|
||||||
|
((req.getServerPort() == 80 || req.getServerPort() == 443) ? "" : ":" + req.getServerPort());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package io.jsonwebtoken.jjwtfun.controller;
|
||||||
|
|
||||||
|
import io.jsonwebtoken.jjwtfun.service.SecretService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.springframework.web.bind.annotation.RequestMethod.GET;
|
||||||
|
import static org.springframework.web.bind.annotation.RequestMethod.POST;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class SecretsController extends BaseController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
SecretService secretService;
|
||||||
|
|
||||||
|
@RequestMapping(value = "/get-secrets", method = GET)
|
||||||
|
public Map<String, String> getSecrets() {
|
||||||
|
return secretService.getSecrets();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(value = "/refresh-secrets", method = GET)
|
||||||
|
public Map<String, String> refreshSecrets() {
|
||||||
|
return secretService.refreshSecrets();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(value = "/set-secrets", method = POST)
|
||||||
|
public Map<String, String> setSecrets(@RequestBody Map<String, String> secrets) {
|
||||||
|
secretService.setSecrets(secrets);
|
||||||
|
return secretService.getSecrets();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
package io.jsonwebtoken.jjwtfun.controller;
|
||||||
|
|
||||||
|
import io.jsonwebtoken.Claims;
|
||||||
|
import io.jsonwebtoken.Jws;
|
||||||
|
import io.jsonwebtoken.Jwts;
|
||||||
|
import io.jsonwebtoken.SignatureAlgorithm;
|
||||||
|
import io.jsonwebtoken.jjwtfun.model.JwtResponse;
|
||||||
|
import io.jsonwebtoken.jjwtfun.service.SecretService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import static org.springframework.web.bind.annotation.RequestMethod.GET;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class StaticJWTController extends BaseController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
SecretService secretService;
|
||||||
|
|
||||||
|
@RequestMapping(value = "/static-builder", method = GET)
|
||||||
|
public JwtResponse fixedBuilder() throws UnsupportedEncodingException {
|
||||||
|
String jws = Jwts.builder()
|
||||||
|
.setIssuer("Stormpath")
|
||||||
|
.setSubject("msilverman")
|
||||||
|
.claim("name", "Micah Silverman")
|
||||||
|
.claim("scope", "admins")
|
||||||
|
.setIssuedAt(Date.from(Instant.ofEpochSecond(1466796822L))) // Fri Jun 24 2016 15:33:42 GMT-0400 (EDT)
|
||||||
|
.setExpiration(Date.from(Instant.ofEpochSecond(4622470422L))) // Sat Jun 24 2116 15:33:42 GMT-0400 (EDT)
|
||||||
|
.signWith(
|
||||||
|
SignatureAlgorithm.HS256,
|
||||||
|
secretService.getHS256SecretBytes()
|
||||||
|
)
|
||||||
|
.compact();
|
||||||
|
|
||||||
|
return new JwtResponse(jws);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(value = "/parser", method = GET)
|
||||||
|
public JwtResponse parser(@RequestParam String jwt) throws UnsupportedEncodingException {
|
||||||
|
|
||||||
|
Jws<Claims> jws = Jwts.parser()
|
||||||
|
.setSigningKeyResolver(secretService.getSigningKeyResolver())
|
||||||
|
.parseClaimsJws(jwt);
|
||||||
|
|
||||||
|
return new JwtResponse(jws);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(value = "/parser-enforce", method = GET)
|
||||||
|
public JwtResponse parserEnforce(@RequestParam String jwt) throws UnsupportedEncodingException {
|
||||||
|
Jws<Claims> jws = Jwts.parser()
|
||||||
|
.requireIssuer("Stormpath")
|
||||||
|
.require("hasMotorcycle", true)
|
||||||
|
.setSigningKeyResolver(secretService.getSigningKeyResolver())
|
||||||
|
.parseClaimsJws(jwt);
|
||||||
|
|
||||||
|
return new JwtResponse(jws);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
package io.jsonwebtoken.jjwtfun.model;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import io.jsonwebtoken.Claims;
|
||||||
|
import io.jsonwebtoken.Jws;
|
||||||
|
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public class JwtResponse {
|
||||||
|
private String message;
|
||||||
|
private Status status;
|
||||||
|
private String exceptionType;
|
||||||
|
private String jwt;
|
||||||
|
private Jws<Claims> jws;
|
||||||
|
|
||||||
|
public enum Status {
|
||||||
|
SUCCESS, ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
public JwtResponse() {}
|
||||||
|
|
||||||
|
public JwtResponse(String jwt) {
|
||||||
|
this.jwt = jwt;
|
||||||
|
this.status = Status.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JwtResponse(Jws<Claims> jws) {
|
||||||
|
this.jws = jws;
|
||||||
|
this.status = Status.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Status getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(Status status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExceptionType() {
|
||||||
|
return exceptionType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExceptionType(String exceptionType) {
|
||||||
|
this.exceptionType = exceptionType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJwt() {
|
||||||
|
return jwt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJwt(String jwt) {
|
||||||
|
this.jwt = jwt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Jws<Claims> getJws() {
|
||||||
|
return jws;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJws(Jws<Claims> jws) {
|
||||||
|
this.jws = jws;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
package io.jsonwebtoken.jjwtfun.service;
|
||||||
|
|
||||||
|
import io.jsonwebtoken.Claims;
|
||||||
|
import io.jsonwebtoken.JwsHeader;
|
||||||
|
import io.jsonwebtoken.SignatureAlgorithm;
|
||||||
|
import io.jsonwebtoken.SigningKeyResolver;
|
||||||
|
import io.jsonwebtoken.SigningKeyResolverAdapter;
|
||||||
|
import io.jsonwebtoken.impl.TextCodec;
|
||||||
|
import io.jsonwebtoken.impl.crypto.MacProvider;
|
||||||
|
import io.jsonwebtoken.lang.Assert;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class SecretService {
|
||||||
|
|
||||||
|
private Map<String, String> secrets = new HashMap<>();
|
||||||
|
|
||||||
|
private SigningKeyResolver signingKeyResolver = new SigningKeyResolverAdapter() {
|
||||||
|
@Override
|
||||||
|
public byte[] resolveSigningKeyBytes(JwsHeader header, Claims claims) {
|
||||||
|
return TextCodec.BASE64.decode(secrets.get(header.getAlgorithm()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void setup() {
|
||||||
|
refreshSecrets();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SigningKeyResolver getSigningKeyResolver() {
|
||||||
|
return signingKeyResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getSecrets() {
|
||||||
|
return secrets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSecrets(Map<String, String> secrets) {
|
||||||
|
Assert.notNull(secrets);
|
||||||
|
Assert.hasText(secrets.get(SignatureAlgorithm.HS256.getValue()));
|
||||||
|
Assert.hasText(secrets.get(SignatureAlgorithm.HS384.getValue()));
|
||||||
|
Assert.hasText(secrets.get(SignatureAlgorithm.HS512.getValue()));
|
||||||
|
|
||||||
|
this.secrets = secrets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getHS256SecretBytes() {
|
||||||
|
return TextCodec.BASE64.decode(secrets.get(SignatureAlgorithm.HS256.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getHS384SecretBytes() {
|
||||||
|
return TextCodec.BASE64.decode(secrets.get(SignatureAlgorithm.HS384.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getHS512SecretBytes() {
|
||||||
|
return TextCodec.BASE64.decode(secrets.get(SignatureAlgorithm.HS384.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Map<String, String> refreshSecrets() {
|
||||||
|
SecretKey key = MacProvider.generateKey(SignatureAlgorithm.HS256);
|
||||||
|
secrets.put(SignatureAlgorithm.HS256.getValue(), TextCodec.BASE64.encode(key.getEncoded()));
|
||||||
|
key = MacProvider.generateKey(SignatureAlgorithm.HS384);
|
||||||
|
secrets.put(SignatureAlgorithm.HS384.getValue(), TextCodec.BASE64.encode(key.getEncoded()));
|
||||||
|
key = MacProvider.generateKey(SignatureAlgorithm.HS512);
|
||||||
|
secrets.put(SignatureAlgorithm.HS512.getValue(), TextCodec.BASE64.encode(key.getEncoded()));
|
||||||
|
return secrets;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<!--/*/ <th:block th:include="fragments/head :: head"/> /*/-->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="box col-md-6 col-md-offset-3">
|
||||||
|
<h1>JWT CSRF Token expired</h1>
|
||||||
|
<h3 th:text="${exception.message}"></h3>
|
||||||
|
|
||||||
|
<a href="/jwt-csrf-form" class="btn btn-primary">Back</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,32 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head th:fragment="head">
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||||
|
<meta name="viewport" content="width=device-width"/>
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300italic,300,400italic,400,600italic,600,700italic,700,800italic,800" rel="stylesheet" type="text/css"/>
|
||||||
|
<link href="https://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet" type="text/css"/>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin-top: 60px;
|
||||||
|
}
|
||||||
|
.box {
|
||||||
|
padding: 50px;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!--[if lt IE 9]>
|
||||||
|
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.2/html5shiv.js"></script>
|
||||||
|
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
|
||||||
|
<![endif]-->
|
||||||
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
|
||||||
|
<script src="https://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>Nothing to see here, move along.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,18 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<!--/*/ <th:block th:include="fragments/head :: head"/> /*/-->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="box col-md-6 col-md-offset-3">
|
||||||
|
<h1>You made it!</h1>
|
||||||
|
<div style="overflow: scroll">
|
||||||
|
<h4 th:text="${csrf}">BLARG</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,18 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<!--/*/ <th:block th:include="fragments/head :: head"/> /*/-->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="box col-md-6 col-md-offset-3">
|
||||||
|
<p/>
|
||||||
|
<form method="post" th:action="@{/jwt-csrf-form}">
|
||||||
|
<input type="submit" class="btn btn-primary" value="Click Me!"/>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,18 @@
|
||||||
|
package io.jsonwebtoken.jjwtfun;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||||
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
import org.springframework.test.context.web.WebAppConfiguration;
|
||||||
|
|
||||||
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
|
@SpringApplicationConfiguration(classes = JJWTFunApplication.class)
|
||||||
|
@WebAppConfiguration
|
||||||
|
public class DemoApplicationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void contextLoads() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
1
pom.xml
1
pom.xml
|
@ -26,6 +26,7 @@
|
||||||
<module>httpclient</module>
|
<module>httpclient</module>
|
||||||
<module>jackson</module>
|
<module>jackson</module>
|
||||||
<module>javaxval</module>
|
<module>javaxval</module>
|
||||||
|
<module>jjwt</module>
|
||||||
<module>jooq-spring</module>
|
<module>jooq-spring</module>
|
||||||
<module>json-path</module>
|
<module>json-path</module>
|
||||||
<module>mockito</module>
|
<module>mockito</module>
|
||||||
|
|
|
@ -10,4 +10,7 @@
|
||||||
# Packaged files #
|
# Packaged files #
|
||||||
*.jar
|
*.jar
|
||||||
*.war
|
*.war
|
||||||
*.ear
|
*.ear
|
||||||
|
|
||||||
|
.externalToolBuilders
|
||||||
|
.settings
|
|
@ -7,48 +7,105 @@
|
||||||
|
|
||||||
<name>rest-assured</name>
|
<name>rest-assured</name>
|
||||||
|
|
||||||
<dependencies>
|
<properties>
|
||||||
|
<!-- maven plugins -->
|
||||||
|
<maven-compiler-plugin.version>3.5.1</maven-compiler-plugin.version>
|
||||||
|
<maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>
|
||||||
|
|
||||||
|
<mockito.version>1.10.19</mockito.version>
|
||||||
|
<junit.version>4.12</junit.version>
|
||||||
|
<wiremock.version>2.1.7</wiremock.version>
|
||||||
|
<hamcrest-all.version>1.3</hamcrest-all.version>
|
||||||
|
<json-schema-core.version>1.2.5</json-schema-core.version>
|
||||||
|
<json-schema-validator.version>2.2.6</json-schema-validator.version>
|
||||||
|
<rest-assured.version>3.0.0</rest-assured.version>
|
||||||
|
|
||||||
|
<!-- logging -->
|
||||||
|
<org.slf4j.version>1.7.13</org.slf4j.version>
|
||||||
|
<logback.version>1.1.3</logback.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- logging -->
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
<version>${org.slf4j.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
<version>${logback.version}</version>
|
||||||
|
<!-- <scope>runtime</scope> -->
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>jcl-over-slf4j</artifactId>
|
||||||
|
<version>${org.slf4j.version}</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency> <!-- needed to bridge to slf4j for projects that use the log4j APIs directly -->
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>log4j-over-slf4j</artifactId>
|
||||||
|
<version>${org.slf4j.version}</version>
|
||||||
|
</dependency>
|
||||||
<!-- utils -->
|
<!-- utils -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.rest-assured</groupId>
|
<groupId>io.rest-assured</groupId>
|
||||||
<artifactId>rest-assured</artifactId>
|
<artifactId>rest-assured</artifactId>
|
||||||
<version>3.0.0</version>
|
<version>${rest-assured.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.rest-assured</groupId>
|
<groupId>io.rest-assured</groupId>
|
||||||
<artifactId>json-schema-validator</artifactId>
|
<artifactId>json-schema-validator</artifactId>
|
||||||
<version>3.0.0</version>
|
<version>${rest-assured.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.fge</groupId>
|
<groupId>com.github.fge</groupId>
|
||||||
<artifactId>json-schema-validator</artifactId>
|
<artifactId>json-schema-validator</artifactId>
|
||||||
<version>2.2.6</version>
|
<version>${json-schema-validator.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.fge</groupId>
|
<groupId>com.github.fge</groupId>
|
||||||
<artifactId>json-schema-core</artifactId>
|
<artifactId>json-schema-core</artifactId>
|
||||||
<version>1.2.5</version>
|
<version>${json-schema-core.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- web -->
|
|
||||||
|
|
||||||
<!-- test scoped -->
|
<!-- test scoped -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>${junit.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>com.github.tomakehurst</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>wiremock</artifactId>
|
||||||
<version>4.3</version>
|
<version>${wiremock.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hamcrest</groupId>
|
<groupId>org.hamcrest</groupId>
|
||||||
<artifactId>hamcrest-all</artifactId>
|
<artifactId>hamcrest-all</artifactId>
|
||||||
<version>1.3</version>
|
<version>${hamcrest-all.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-core</artifactId>
|
||||||
|
<version>${mockito.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
|
@ -1,20 +1,23 @@
|
||||||
package com.baeldung.restassured;
|
package com.baeldung.restassured;
|
||||||
|
|
||||||
import static io.restassured.RestAssured.get;
|
|
||||||
import static io.restassured.RestAssured.post;
|
|
||||||
import static io.restassured.module.jsv.JsonSchemaValidator.matchesJsonSchemaInClasspath;
|
|
||||||
import static io.restassured.module.jsv.JsonSchemaValidatorSettings.settings;
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
|
||||||
import static org.hamcrest.Matchers.hasItems;
|
|
||||||
import static org.hamcrest.Matchers.containsString;
|
|
||||||
import io.restassured.module.jsv.JsonSchemaValidator;
|
|
||||||
import static org.hamcrest.xml.HasXPath.hasXPath;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import com.github.fge.jsonschema.SchemaVersion;
|
import com.github.fge.jsonschema.SchemaVersion;
|
||||||
import com.github.fge.jsonschema.cfg.ValidationConfiguration;
|
import com.github.fge.jsonschema.cfg.ValidationConfiguration;
|
||||||
import com.github.fge.jsonschema.main.JsonSchemaFactory;
|
import com.github.fge.jsonschema.main.JsonSchemaFactory;
|
||||||
|
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||||
|
import com.github.tomakehurst.wiremock.client.WireMock;
|
||||||
|
import io.restassured.module.jsv.JsonSchemaValidator;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static com.github.tomakehurst.wiremock.client.WireMock.*;
|
||||||
|
import static io.restassured.RestAssured.get;
|
||||||
|
import static io.restassured.RestAssured.post;
|
||||||
|
import static io.restassured.module.jsv.JsonSchemaValidator.matchesJsonSchemaInClasspath;
|
||||||
|
import static io.restassured.module.jsv.JsonSchemaValidatorSettings.settings;
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.hamcrest.xml.HasXPath.hasXPath;
|
||||||
|
|
||||||
|
|
||||||
public class RestAssuredTest {
|
public class RestAssuredTest {
|
||||||
|
|
||||||
|
@ -36,29 +39,81 @@ public class RestAssuredTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private WireMockServer wireMockServer = new WireMockServer();
|
||||||
|
private static final String EVENTS_PATH = "/events?id=390";
|
||||||
|
private static final String APPLICATION_JSON = "application/json";
|
||||||
|
|
||||||
|
private static final String GAME_ODDS = "" +
|
||||||
|
"{" +
|
||||||
|
" \"id\": 390," +
|
||||||
|
" \"data\": {" +
|
||||||
|
" \"countryId\": 35," +
|
||||||
|
" \"countryName\": \"Norway\"," +
|
||||||
|
" \"leagueName\": \"Norway 3\"," +
|
||||||
|
" \"status\": 0," +
|
||||||
|
" \"sportName\": \"Soccer\"," +
|
||||||
|
" \"time\": \"2016-06-12T12:00:00Z\"" +
|
||||||
|
" }," +
|
||||||
|
" \"odds\": [" +
|
||||||
|
" {" +
|
||||||
|
" \"price\": \"1.30\"," +
|
||||||
|
" \"status\": 0," +
|
||||||
|
" \"ck\": \"1\"," +
|
||||||
|
" \"name\": \"1\"" +
|
||||||
|
" }," +
|
||||||
|
" {" +
|
||||||
|
" \"price\": \"5.25\"," +
|
||||||
|
" \"status\": 0," +
|
||||||
|
" \"ck\": \"X\"," +
|
||||||
|
" \"name\": \"X\"" +
|
||||||
|
" }" +
|
||||||
|
" ]" +
|
||||||
|
"}";
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenUrl_whenSuccessOnGetsResponse_andJsonHasRequiredKV_thenCorrect() {
|
public void givenUrl_whenSuccessOnGetsResponse_andJsonHasRequiredKV_thenCorrect() {
|
||||||
|
|
||||||
|
wireMockServer.start();
|
||||||
|
configureFor("localhost", 8080);
|
||||||
|
|
||||||
|
stubFor(WireMock.get(urlEqualTo(EVENTS_PATH)).willReturn(aResponse()
|
||||||
|
.withStatus(200)
|
||||||
|
.withHeader("Content-Type", APPLICATION_JSON)
|
||||||
|
.withBody(GAME_ODDS)));
|
||||||
|
|
||||||
get("/events?id=390").then().statusCode(200).assertThat()
|
get("/events?id=390").then().statusCode(200).assertThat()
|
||||||
.body("data.id", equalTo(390));
|
.body("id", equalTo(390));
|
||||||
|
|
||||||
|
wireMockServer.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenUrl_whenJsonResponseHasArrayWithGivenValuesUnderKey_thenCorrect() {
|
public void givenUrl_whenJsonResponseHasArrayWithGivenValuesUnderKey_thenCorrect() {
|
||||||
|
|
||||||
get("/events?id=390").then().assertThat()
|
wireMockServer.start();
|
||||||
.body("odds.price", hasItems("1.30", "5.25"));
|
configureFor("localhost", 8080);
|
||||||
|
|
||||||
|
stubFor(WireMock.get(urlEqualTo(EVENTS_PATH)).willReturn(aResponse()
|
||||||
|
.withStatus(200)
|
||||||
|
.withHeader("Content-Type", APPLICATION_JSON)
|
||||||
|
.withBody(GAME_ODDS)));
|
||||||
|
|
||||||
|
get("/events?id=390").then().assertThat()
|
||||||
|
.body("odds.price", hasItems("1.30", "5.25"));
|
||||||
|
|
||||||
|
wireMockServer.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
|
@Test @Ignore
|
||||||
public void givenUrl_whenJsonResponseConformsToSchema_thenCorrect() {
|
public void givenUrl_whenJsonResponseConformsToSchema_thenCorrect() {
|
||||||
get("/events?id=390").then().assertThat()
|
get("/events?id=390").then().assertThat()
|
||||||
.body(matchesJsonSchemaInClasspath("event_0.json"));
|
.body(matchesJsonSchemaInClasspath("event_0.json"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test @Ignore
|
||||||
public void givenUrl_whenValidatesResponseWithInstanceSettings_thenCorrect() {
|
public void givenUrl_whenValidatesResponseWithInstanceSettings_thenCorrect() {
|
||||||
JsonSchemaFactory jsonSchemaFactory = JsonSchemaFactory
|
JsonSchemaFactory jsonSchemaFactory = JsonSchemaFactory
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
|
@ -75,7 +130,7 @@ public class RestAssuredTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test @Ignore
|
||||||
public void givenUrl_whenValidatesResponseWithStaticSettings_thenCorrect() {
|
public void givenUrl_whenValidatesResponseWithStaticSettings_thenCorrect() {
|
||||||
|
|
||||||
get("/events?id=390")
|
get("/events?id=390")
|
||||||
|
@ -86,18 +141,18 @@ public class RestAssuredTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test @Ignore
|
||||||
public void givenUrl_whenCheckingFloatValuePasses_thenCorrect() {
|
public void givenUrl_whenCheckingFloatValuePasses_thenCorrect() {
|
||||||
get("/odd").then().assertThat().body("odd.ck", equalTo(12.2f));
|
get("/odd").then().assertThat().body("odd.ck", equalTo(12.2f));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test @Ignore
|
||||||
public void givenUrl_whenXmlResponseValueTestsEqual_thenCorrect() {
|
public void givenUrl_whenXmlResponseValueTestsEqual_thenCorrect() {
|
||||||
post("/employees").then().assertThat()
|
post("/employees").then().assertThat()
|
||||||
.body("employees.employee.first-name", equalTo("Jane"));
|
.body("employees.employee.first-name", equalTo("Jane"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test @Ignore
|
||||||
public void givenUrl_whenMultipleXmlValuesTestEqual_thenCorrect() {
|
public void givenUrl_whenMultipleXmlValuesTestEqual_thenCorrect() {
|
||||||
post("/employees").then().assertThat()
|
post("/employees").then().assertThat()
|
||||||
.body("employees.employee.first-name", equalTo("Jane"))
|
.body("employees.employee.first-name", equalTo("Jane"))
|
||||||
|
@ -105,7 +160,7 @@ public class RestAssuredTest {
|
||||||
.body("employees.employee.sex", equalTo("f"));
|
.body("employees.employee.sex", equalTo("f"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test @Ignore
|
||||||
public void givenUrl_whenMultipleXmlValuesTestEqualInShortHand_thenCorrect() {
|
public void givenUrl_whenMultipleXmlValuesTestEqualInShortHand_thenCorrect() {
|
||||||
post("/employees")
|
post("/employees")
|
||||||
.then()
|
.then()
|
||||||
|
@ -115,7 +170,7 @@ public class RestAssuredTest {
|
||||||
"employees.employee.sex", equalTo("f"));
|
"employees.employee.sex", equalTo("f"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test @Ignore
|
||||||
public void givenUrl_whenValidatesXmlUsingXpath_thenCorrect() {
|
public void givenUrl_whenValidatesXmlUsingXpath_thenCorrect() {
|
||||||
post("/employees")
|
post("/employees")
|
||||||
.then()
|
.then()
|
||||||
|
@ -125,7 +180,7 @@ public class RestAssuredTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test @Ignore
|
||||||
public void givenUrl_whenValidatesXmlUsingXpath2_thenCorrect() {
|
public void givenUrl_whenValidatesXmlUsingXpath2_thenCorrect() {
|
||||||
post("/employees")
|
post("/employees")
|
||||||
.then()
|
.then()
|
||||||
|
@ -134,7 +189,7 @@ public class RestAssuredTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test @Ignore
|
||||||
public void givenUrl_whenVerifiesScienceTeacherFromXml_thenCorrect() {
|
public void givenUrl_whenVerifiesScienceTeacherFromXml_thenCorrect() {
|
||||||
get("/teachers")
|
get("/teachers")
|
||||||
.then()
|
.then()
|
||||||
|
@ -142,7 +197,7 @@ public class RestAssuredTest {
|
||||||
hasItems("math", "physics"));
|
hasItems("math", "physics"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test @Ignore
|
||||||
public void givenUrl_whenVerifiesOddPricesAccuratelyByStatus_thenCorrect() {
|
public void givenUrl_whenVerifiesOddPricesAccuratelyByStatus_thenCorrect() {
|
||||||
get("/odds").then().body("odds.findAll { it.status > 0 }.price",
|
get("/odds").then().body("odds.findAll { it.status > 0 }.price",
|
||||||
hasItems(1.30f, 1.20f));
|
hasItems(1.30f, 1.20f));
|
||||||
|
|
Loading…
Reference in New Issue