diff --git a/jackson/.classpath b/jackson/.classpath index 8ebf6d9c31..5efa587d72 100644 --- a/jackson/.classpath +++ b/jackson/.classpath @@ -29,7 +29,7 @@ - + diff --git a/jackson/pom.xml b/jackson/pom.xml index c7cd172757..17b0ac507e 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -109,6 +109,31 @@ ${mockito.version} test + + + + + org.slf4j + slf4j-api + ${org.slf4j.version} + + + ch.qos.logback + logback-classic + ${logback.version} + + + + org.slf4j + jcl-over-slf4j + ${org.slf4j.version} + + + + org.slf4j + log4j-over-slf4j + ${org.slf4j.version} + diff --git a/jackson/src/test/java/com/baeldung/jackson/objectmapper/CustomCarDeserializer.java b/jackson/src/test/java/com/baeldung/jackson/objectmapper/CustomCarDeserializer.java new file mode 100644 index 0000000000..88ee1cd673 --- /dev/null +++ b/jackson/src/test/java/com/baeldung/jackson/objectmapper/CustomCarDeserializer.java @@ -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 { + 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; + } +} diff --git a/jackson/src/test/java/com/baeldung/jackson/objectmapper/CustomCarSerializer.java b/jackson/src/test/java/com/baeldung/jackson/objectmapper/CustomCarSerializer.java new file mode 100644 index 0000000000..08c7184d29 --- /dev/null +++ b/jackson/src/test/java/com/baeldung/jackson/objectmapper/CustomCarSerializer.java @@ -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 +{ + 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(); + } +} diff --git a/jackson/src/test/java/com/baeldung/jackson/objectmapper/TestJavaReadWriteJsonExample.java b/jackson/src/test/java/com/baeldung/jackson/objectmapper/TestJavaReadWriteJsonExample.java new file mode 100644 index 0000000000..54ddf469c8 --- /dev/null +++ b/jackson/src/test/java/com/baeldung/jackson/objectmapper/TestJavaReadWriteJsonExample.java @@ -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 listCar = objectMapper.readValue(LOCAL_JSON, new TypeReference>() { + + }); + 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 map = objectMapper.readValue(EXAMPLE_JSON, new TypeReference>() { + }); + assertNotNull(map); + for (final String key : map.keySet()) { + assertNotNull(key); + } + } +} diff --git a/jackson/src/test/java/com/baeldung/jackson/objectmapper/TestSerializationDeserializationFeature.java b/jackson/src/test/java/com/baeldung/jackson/objectmapper/TestSerializationDeserializationFeature.java new file mode 100644 index 0000000000..96918f4c28 --- /dev/null +++ b/jackson/src/test/java/com/baeldung/jackson/objectmapper/TestSerializationDeserializationFeature.java @@ -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")); + } + } +} diff --git a/jackson/src/test/java/com/baeldung/jackson/objectmapper/dto/Car.java b/jackson/src/test/java/com/baeldung/jackson/objectmapper/dto/Car.java new file mode 100644 index 0000000000..bf4309439b --- /dev/null +++ b/jackson/src/test/java/com/baeldung/jackson/objectmapper/dto/Car.java @@ -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; + } +} diff --git a/jackson/src/test/java/com/baeldung/jackson/objectmapper/dto/Request.java b/jackson/src/test/java/com/baeldung/jackson/objectmapper/dto/Request.java new file mode 100644 index 0000000000..2a4cce0fdd --- /dev/null +++ b/jackson/src/test/java/com/baeldung/jackson/objectmapper/dto/Request.java @@ -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; + } +} \ No newline at end of file diff --git a/jjwt/.gitignore b/jjwt/.gitignore new file mode 100644 index 0000000000..f83e8cf07c --- /dev/null +++ b/jjwt/.gitignore @@ -0,0 +1,3 @@ +.idea +target +*.iml diff --git a/jjwt/README.md b/jjwt/README.md new file mode 100644 index 0000000000..47b51038a8 --- /dev/null +++ b/jjwt/README.md @@ -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= + Parse passed in JWT + + http http://localhost:8080/parser-enforce?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/) \ No newline at end of file diff --git a/jjwt/pom.xml b/jjwt/pom.xml new file mode 100644 index 0000000000..24f1c5c5ab --- /dev/null +++ b/jjwt/pom.xml @@ -0,0 +1,65 @@ + + + 4.0.0 + + io.jsonwebtoken + jjwtfun + 0.0.1-SNAPSHOT + jar + + jjwtfun + Exercising the JJWT + + + org.springframework.boot + spring-boot-starter-parent + 1.3.5.RELEASE + + + + + UTF-8 + 1.8 + + + + + org.springframework.boot + spring-boot-devtools + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + org.springframework.boot + spring-boot-starter-security + + + + org.springframework.boot + spring-boot-starter-test + test + + + + io.jsonwebtoken + jjwt + 0.6.0 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/JJWTFunApplication.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/JJWTFunApplication.java new file mode 100644 index 0000000000..5c106aac70 --- /dev/null +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/JJWTFunApplication.java @@ -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); + } +} diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/CSRFConfig.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/CSRFConfig.java new file mode 100644 index 0000000000..7d88835243 --- /dev/null +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/CSRFConfig.java @@ -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()); + } +} diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/JWTCsrfTokenRepository.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/JWTCsrfTokenRepository.java new file mode 100644 index 0000000000..bf88b8aff1 --- /dev/null +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/JWTCsrfTokenRepository.java @@ -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); + } +} diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/WebSecurityConfig.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/WebSecurityConfig.java new file mode 100644 index 0000000000..94e2c6ddc5 --- /dev/null +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/config/WebSecurityConfig.java @@ -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); + } + } +} diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/BaseController.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/BaseController.java new file mode 100644 index 0000000000..e1e195c6ab --- /dev/null +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/BaseController.java @@ -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; + } +} diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/DynamicJWTController.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/DynamicJWTController.java new file mode 100644 index 0000000000..c03c63dd80 --- /dev/null +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/DynamicJWTController.java @@ -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 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 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 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); + } + } +} diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/FormController.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/FormController.java new file mode 100644 index 0000000000..54123c63cb --- /dev/null +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/FormController.java @@ -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"; + } +} diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/HomeController.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/HomeController.java new file mode 100644 index 0000000000..57cd14385e --- /dev/null +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/HomeController.java @@ -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=\n\tParse passed in JWT\n\n" + + " http " + requestUrl + "/parser-enforce?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()); + } +} diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/SecretsController.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/SecretsController.java new file mode 100644 index 0000000000..1ca0973c33 --- /dev/null +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/SecretsController.java @@ -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 getSecrets() { + return secretService.getSecrets(); + } + + @RequestMapping(value = "/refresh-secrets", method = GET) + public Map refreshSecrets() { + return secretService.refreshSecrets(); + } + + @RequestMapping(value = "/set-secrets", method = POST) + public Map setSecrets(@RequestBody Map secrets) { + secretService.setSecrets(secrets); + return secretService.getSecrets(); + } +} diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/StaticJWTController.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/StaticJWTController.java new file mode 100644 index 0000000000..83f5336978 --- /dev/null +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/controller/StaticJWTController.java @@ -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 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 jws = Jwts.parser() + .requireIssuer("Stormpath") + .require("hasMotorcycle", true) + .setSigningKeyResolver(secretService.getSigningKeyResolver()) + .parseClaimsJws(jwt); + + return new JwtResponse(jws); + } +} diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/model/JwtResponse.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/model/JwtResponse.java new file mode 100644 index 0000000000..491f003289 --- /dev/null +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/model/JwtResponse.java @@ -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 jws; + + public enum Status { + SUCCESS, ERROR + } + + public JwtResponse() {} + + public JwtResponse(String jwt) { + this.jwt = jwt; + this.status = Status.SUCCESS; + } + + public JwtResponse(Jws 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 getJws() { + return jws; + } + + public void setJws(Jws jws) { + this.jws = jws; + } +} diff --git a/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/service/SecretService.java b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/service/SecretService.java new file mode 100644 index 0000000000..4311afa592 --- /dev/null +++ b/jjwt/src/main/java/io/jsonwebtoken/jjwtfun/service/SecretService.java @@ -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 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 getSecrets() { + return secrets; + } + + public void setSecrets(Map 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 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; + } +} diff --git a/jjwt/src/main/resources/application.properties b/jjwt/src/main/resources/application.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/jjwt/src/main/resources/templates/expired-jwt.html b/jjwt/src/main/resources/templates/expired-jwt.html new file mode 100644 index 0000000000..7bf9ff258e --- /dev/null +++ b/jjwt/src/main/resources/templates/expired-jwt.html @@ -0,0 +1,17 @@ + + + + + +
+
+
+

JWT CSRF Token expired

+

+ + Back +
+
+
+ + \ No newline at end of file diff --git a/jjwt/src/main/resources/templates/fragments/head.html b/jjwt/src/main/resources/templates/fragments/head.html new file mode 100644 index 0000000000..2d5f54e5a0 --- /dev/null +++ b/jjwt/src/main/resources/templates/fragments/head.html @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + +

Nothing to see here, move along.

+ + \ No newline at end of file diff --git a/jjwt/src/main/resources/templates/jwt-csrf-form-result.html b/jjwt/src/main/resources/templates/jwt-csrf-form-result.html new file mode 100644 index 0000000000..cfb832bf7c --- /dev/null +++ b/jjwt/src/main/resources/templates/jwt-csrf-form-result.html @@ -0,0 +1,18 @@ + + + + + + +
+
+
+

You made it!

+
+

BLARG

+
+
+
+
+ + \ No newline at end of file diff --git a/jjwt/src/main/resources/templates/jwt-csrf-form.html b/jjwt/src/main/resources/templates/jwt-csrf-form.html new file mode 100644 index 0000000000..235f6063c9 --- /dev/null +++ b/jjwt/src/main/resources/templates/jwt-csrf-form.html @@ -0,0 +1,18 @@ + + + + + + +
+
+
+

+

+ +
+
+
+
+ + \ No newline at end of file diff --git a/jjwt/src/test/java/io/jsonwebtoken/jjwtfun/DemoApplicationTests.java b/jjwt/src/test/java/io/jsonwebtoken/jjwtfun/DemoApplicationTests.java new file mode 100644 index 0000000000..82138ea23e --- /dev/null +++ b/jjwt/src/test/java/io/jsonwebtoken/jjwtfun/DemoApplicationTests.java @@ -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() { + } + +} diff --git a/pom.xml b/pom.xml index 26ceec36d3..82cf85208c 100644 --- a/pom.xml +++ b/pom.xml @@ -26,6 +26,7 @@ httpclient jackson javaxval + jjwt jooq-spring json-path mockito diff --git a/rest-assured-tutorial/.gitignore b/rest-assured-tutorial/.gitignore index 83c05e60c8..862f46031e 100644 --- a/rest-assured-tutorial/.gitignore +++ b/rest-assured-tutorial/.gitignore @@ -10,4 +10,7 @@ # Packaged files # *.jar *.war -*.ear \ No newline at end of file +*.ear + +.externalToolBuilders +.settings \ No newline at end of file diff --git a/rest-assured-tutorial/pom.xml b/rest-assured-tutorial/pom.xml index 12c1fe25ca..51b22fa0ff 100644 --- a/rest-assured-tutorial/pom.xml +++ b/rest-assured-tutorial/pom.xml @@ -7,48 +7,105 @@ rest-assured - + + + 3.5.1 + 2.19.1 + 1.10.19 + 4.12 + 2.1.7 + 1.3 + 1.2.5 + 2.2.6 + 3.0.0 + + + 1.7.13 + 1.1.3 + + + + + + + org.slf4j + slf4j-api + ${org.slf4j.version} + + + ch.qos.logback + logback-classic + ${logback.version} + + + + org.slf4j + jcl-over-slf4j + ${org.slf4j.version} + runtime + + + org.slf4j + log4j-over-slf4j + ${org.slf4j.version} + io.rest-assured rest-assured - 3.0.0 + ${rest-assured.version} test + io.rest-assured json-schema-validator - 3.0.0 + ${rest-assured.version} + com.github.fge json-schema-validator - 2.2.6 + ${json-schema-validator.version} + com.github.fge json-schema-core - 1.2.5 + ${json-schema-core.version} - + + junit + junit + ${junit.version} + test + - - junit - junit - 4.3 - test - + + com.github.tomakehurst + wiremock + ${wiremock.version} + test + org.hamcrest hamcrest-all - 1.3 + ${hamcrest-all.version} + test + + org.mockito + mockito-core + ${mockito.version} + test + + diff --git a/rest-assured-tutorial/src/test/java/com/baeldung/restassured/RestAssuredTest.java b/rest-assured-tutorial/src/test/java/com/baeldung/restassured/RestAssuredTest.java index 55c7a6f0d0..6ac2d91ee0 100644 --- a/rest-assured-tutorial/src/test/java/com/baeldung/restassured/RestAssuredTest.java +++ b/rest-assured-tutorial/src/test/java/com/baeldung/restassured/RestAssuredTest.java @@ -1,20 +1,23 @@ 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.cfg.ValidationConfiguration; 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 { @@ -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 - 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() - .body("data.id", equalTo(390)); + .body("id", equalTo(390)); + wireMockServer.stop(); } + @Test public void givenUrl_whenJsonResponseHasArrayWithGivenValuesUnderKey_thenCorrect() { - get("/events?id=390").then().assertThat() - .body("odds.price", hasItems("1.30", "5.25")); + 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().assertThat() + .body("odds.price", hasItems("1.30", "5.25")); + + wireMockServer.stop(); } - @Test + + @Test @Ignore public void givenUrl_whenJsonResponseConformsToSchema_thenCorrect() { get("/events?id=390").then().assertThat() .body(matchesJsonSchemaInClasspath("event_0.json")); } - @Test + @Test @Ignore public void givenUrl_whenValidatesResponseWithInstanceSettings_thenCorrect() { JsonSchemaFactory jsonSchemaFactory = JsonSchemaFactory .newBuilder() @@ -75,7 +130,7 @@ public class RestAssuredTest { } - @Test + @Test @Ignore public void givenUrl_whenValidatesResponseWithStaticSettings_thenCorrect() { get("/events?id=390") @@ -86,18 +141,18 @@ public class RestAssuredTest { } - @Test + @Test @Ignore public void givenUrl_whenCheckingFloatValuePasses_thenCorrect() { get("/odd").then().assertThat().body("odd.ck", equalTo(12.2f)); } - @Test + @Test @Ignore public void givenUrl_whenXmlResponseValueTestsEqual_thenCorrect() { post("/employees").then().assertThat() .body("employees.employee.first-name", equalTo("Jane")); } - @Test + @Test @Ignore public void givenUrl_whenMultipleXmlValuesTestEqual_thenCorrect() { post("/employees").then().assertThat() .body("employees.employee.first-name", equalTo("Jane")) @@ -105,7 +160,7 @@ public class RestAssuredTest { .body("employees.employee.sex", equalTo("f")); } - @Test + @Test @Ignore public void givenUrl_whenMultipleXmlValuesTestEqualInShortHand_thenCorrect() { post("/employees") .then() @@ -115,7 +170,7 @@ public class RestAssuredTest { "employees.employee.sex", equalTo("f")); } - @Test + @Test @Ignore public void givenUrl_whenValidatesXmlUsingXpath_thenCorrect() { post("/employees") .then() @@ -125,7 +180,7 @@ public class RestAssuredTest { } - @Test + @Test @Ignore public void givenUrl_whenValidatesXmlUsingXpath2_thenCorrect() { post("/employees") .then() @@ -134,7 +189,7 @@ public class RestAssuredTest { } - @Test + @Test @Ignore public void givenUrl_whenVerifiesScienceTeacherFromXml_thenCorrect() { get("/teachers") .then() @@ -142,7 +197,7 @@ public class RestAssuredTest { hasItems("math", "physics")); } - @Test + @Test @Ignore public void givenUrl_whenVerifiesOddPricesAccuratelyByStatus_thenCorrect() { get("/odds").then().body("odds.findAll { it.status > 0 }.price", hasItems(1.30f, 1.20f));