commit
4ed5e99f4e
@ -11,3 +11,4 @@ This module contains articles about Apache POI
|
|||||||
- [Get String Value of Excel Cell with Apache POI](https://www.baeldung.com/java-apache-poi-cell-string-value)
|
- [Get String Value of Excel Cell with Apache POI](https://www.baeldung.com/java-apache-poi-cell-string-value)
|
||||||
- [Read Excel Cell Value Rather Than Formula With Apache POI](https://www.baeldung.com/apache-poi-read-cell-value-formula)
|
- [Read Excel Cell Value Rather Than Formula With Apache POI](https://www.baeldung.com/apache-poi-read-cell-value-formula)
|
||||||
- [Setting Formulas in Excel with Apache POI](https://www.baeldung.com/java-apache-poi-set-formulas)
|
- [Setting Formulas in Excel with Apache POI](https://www.baeldung.com/java-apache-poi-set-formulas)
|
||||||
|
- [Insert a Row in Excel Using Apache POI](https://www.baeldung.com/apache-poi-insert-excel-row)
|
||||||
|
@ -5,3 +5,4 @@
|
|||||||
### Relevant Articles:
|
### Relevant Articles:
|
||||||
|
|
||||||
- [ArrayList vs. LinkedList vs. HashMap in Java](https://www.baeldung.com/java-arraylist-vs-linkedlist-vs-hashmap)
|
- [ArrayList vs. LinkedList vs. HashMap in Java](https://www.baeldung.com/java-arraylist-vs-linkedlist-vs-hashmap)
|
||||||
|
- [Java Deque vs. Stack](https://www.baeldung.com/java-deque-vs-stack)
|
||||||
|
@ -8,4 +8,5 @@ This module contains articles about Map data structures in Java.
|
|||||||
- [The Map.computeIfAbsent() Method](https://www.baeldung.com/java-map-computeifabsent)
|
- [The Map.computeIfAbsent() Method](https://www.baeldung.com/java-map-computeifabsent)
|
||||||
- [Collections.synchronizedMap vs. ConcurrentHashMap](https://www.baeldung.com/java-synchronizedmap-vs-concurrenthashmap)
|
- [Collections.synchronizedMap vs. ConcurrentHashMap](https://www.baeldung.com/java-synchronizedmap-vs-concurrenthashmap)
|
||||||
- [Java HashMap Load Factor](https://www.baeldung.com/java-hashmap-load-factor)
|
- [Java HashMap Load Factor](https://www.baeldung.com/java-hashmap-load-factor)
|
||||||
|
- [Converting java.util.Properties to HashMap](https://www.baeldung.com/java-convert-properties-to-hashmap)
|
||||||
- More articles: [[<-- prev]](/core-java-modules/core-java-collections-maps-2)
|
- More articles: [[<-- prev]](/core-java-modules/core-java-collections-maps-2)
|
||||||
|
@ -5,12 +5,12 @@ import com.google.common.io.CharSource;
|
|||||||
import com.google.common.io.Files;
|
import com.google.common.io.Files;
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.commons.io.input.ReaderInputStream;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
public class JavaXToInputStreamUnitTest {
|
public class JavaXToInputStreamUnitTest {
|
||||||
protected final Logger logger = LoggerFactory.getLogger(getClass());
|
protected final Logger logger = LoggerFactory.getLogger(getClass());
|
||||||
@ -28,7 +28,7 @@ public class JavaXToInputStreamUnitTest {
|
|||||||
@Test
|
@Test
|
||||||
public final void givenUsingGuava_whenConvertingStringToInputStream_thenCorrect() throws IOException {
|
public final void givenUsingGuava_whenConvertingStringToInputStream_thenCorrect() throws IOException {
|
||||||
final String initialString = "text";
|
final String initialString = "text";
|
||||||
final InputStream targetStream = new ReaderInputStream(CharSource.wrap(initialString).openStream());
|
final InputStream targetStream = CharSource.wrap(initialString).asByteSource(StandardCharsets.UTF_8).openStream();
|
||||||
|
|
||||||
IOUtils.closeQuietly(targetStream);
|
IOUtils.closeQuietly(targetStream);
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,15 @@
|
|||||||
<relativePath>../</relativePath>
|
<relativePath>../</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-test</artifactId>
|
||||||
|
<version>${spring.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<finalName>core-java-reflection-2</finalName>
|
<finalName>core-java-reflection-2</finalName>
|
||||||
<resources>
|
<resources>
|
||||||
@ -40,5 +49,6 @@
|
|||||||
<maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
|
<maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
|
||||||
<source.version>1.8</source.version>
|
<source.version>1.8</source.version>
|
||||||
<target.version>1.8</target.version>
|
<target.version>1.8</target.version>
|
||||||
|
<spring.version>5.3.4</spring.version>
|
||||||
</properties>
|
</properties>
|
||||||
</project>
|
</project>
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.baeldung.reflection.access.privatemethods;
|
||||||
|
|
||||||
|
public class LongArrayUtil {
|
||||||
|
|
||||||
|
public static int indexOf(long[] array, long target) {
|
||||||
|
return indexOf(array, target, 0, array.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int indexOf(long[] array, long target, int start, int end) {
|
||||||
|
for (int i = start; i < end; i++) {
|
||||||
|
if (array[i] == target) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.baeldung.reflection.access.privatemethods;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
class InvokePrivateMethodsUnitTest {
|
||||||
|
|
||||||
|
private final long[] someLongArray = new long[] { 1L, 2L, 1L, 4L, 2L };
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenSearchingForLongValueInSubsequenceUsingReflection_thenTheCorrectIndexOfTheValueIsReturned() throws Exception {
|
||||||
|
Method indexOfMethod = LongArrayUtil.class.getDeclaredMethod("indexOf", long[].class, long.class, int.class, int.class);
|
||||||
|
indexOfMethod.setAccessible(true);
|
||||||
|
|
||||||
|
assertEquals(2, indexOfMethod.invoke(LongArrayUtil.class, someLongArray, 1L, 1, someLongArray.length), "The index should be 2.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenSearchingForLongValueInSubsequenceUsingSpring_thenTheCorrectIndexOfTheValueIsReturned() throws Exception {
|
||||||
|
int indexOfSearchTarget = ReflectionTestUtils.invokeMethod(LongArrayUtil.class, "indexOf", someLongArray, 1L, 1, someLongArray.length);
|
||||||
|
assertEquals(2, indexOfSearchTarget, "The index should be 2.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -15,4 +15,5 @@ This module contains articles about core Java Security
|
|||||||
- [Security Context Basics: User, Subject and Principal](https://www.baeldung.com/security-context-basics)
|
- [Security Context Basics: User, Subject and Principal](https://www.baeldung.com/security-context-basics)
|
||||||
- [Java AES Encryption and Decryption](https://www.baeldung.com/java-aes-encryption-decryption)
|
- [Java AES Encryption and Decryption](https://www.baeldung.com/java-aes-encryption-decryption)
|
||||||
- [InvalidAlgorithmParameterException: Wrong IV Length](https://www.baeldung.com/java-invalidalgorithmparameter-exception)
|
- [InvalidAlgorithmParameterException: Wrong IV Length](https://www.baeldung.com/java-invalidalgorithmparameter-exception)
|
||||||
|
- [The java.security.egd JVM Option](https://www.baeldung.com/java-security-egd)
|
||||||
- More articles: [[<-- prev]](/core-java-modules/core-java-security)
|
- More articles: [[<-- prev]](/core-java-modules/core-java-security)
|
||||||
|
@ -5,7 +5,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
public class CircularLinkedList {
|
public class CircularLinkedList {
|
||||||
|
|
||||||
final Logger LOGGER = LoggerFactory.getLogger(CircularLinkedList.class);
|
final Logger logger = LoggerFactory.getLogger(CircularLinkedList.class);
|
||||||
|
|
||||||
private Node head = null;
|
private Node head = null;
|
||||||
private Node tail = null;
|
private Node tail = null;
|
||||||
@ -42,25 +42,30 @@ public class CircularLinkedList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void deleteNode(int valueToDelete) {
|
public void deleteNode(int valueToDelete) {
|
||||||
|
|
||||||
Node currentNode = head;
|
Node currentNode = head;
|
||||||
|
if (head == null) {
|
||||||
if (head != null) {
|
return;
|
||||||
if (currentNode.value == valueToDelete) {
|
}
|
||||||
head = head.nextNode;
|
|
||||||
tail.nextNode = head;
|
|
||||||
} else {
|
|
||||||
do {
|
do {
|
||||||
Node nextNode = currentNode.nextNode;
|
Node nextNode = currentNode.nextNode;
|
||||||
if (nextNode.value == valueToDelete) {
|
if (nextNode.value == valueToDelete) {
|
||||||
|
if (tail == head) {
|
||||||
|
head = null;
|
||||||
|
tail = null;
|
||||||
|
} else {
|
||||||
currentNode.nextNode = nextNode.nextNode;
|
currentNode.nextNode = nextNode.nextNode;
|
||||||
|
if (head == nextNode) {
|
||||||
|
head = head.nextNode;
|
||||||
|
}
|
||||||
|
if (tail == nextNode) {
|
||||||
|
tail = currentNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
currentNode = currentNode.nextNode;
|
currentNode = nextNode;
|
||||||
} while (currentNode != head);
|
} while (currentNode != head);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void traverseList() {
|
public void traverseList() {
|
||||||
|
|
||||||
@ -68,7 +73,7 @@ public class CircularLinkedList {
|
|||||||
|
|
||||||
if (head != null) {
|
if (head != null) {
|
||||||
do {
|
do {
|
||||||
LOGGER.info(currentNode.value + " ");
|
logger.info(currentNode.value + " ");
|
||||||
currentNode = currentNode.nextNode;
|
currentNode = currentNode.nextNode;
|
||||||
} while (currentNode != head);
|
} while (currentNode != head);
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package com.baeldung.circularlinkedlist;
|
package com.baeldung.circularlinkedlist;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
public class CircularLinkedListUnitTest {
|
public class CircularLinkedListUnitTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -23,7 +23,7 @@ public class CircularLinkedListUnitTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenACircularLinkedList_WhenDeletingElements_ThenListDoesNotContainThoseElements() {
|
public void givenACircularLinkedList_WhenDeletingInOrderHeadMiddleTail_ThenListDoesNotContainThoseElements() {
|
||||||
CircularLinkedList cll = createCircularLinkedList();
|
CircularLinkedList cll = createCircularLinkedList();
|
||||||
|
|
||||||
assertTrue(cll.containsNode(13));
|
assertTrue(cll.containsNode(13));
|
||||||
@ -39,6 +39,32 @@ public class CircularLinkedListUnitTest {
|
|||||||
assertFalse(cll.containsNode(46));
|
assertFalse(cll.containsNode(46));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenACircularLinkedList_WhenDeletingInOrderTailMiddleHead_ThenListDoesNotContainThoseElements() {
|
||||||
|
CircularLinkedList cll = createCircularLinkedList();
|
||||||
|
|
||||||
|
assertTrue(cll.containsNode(46));
|
||||||
|
cll.deleteNode(46);
|
||||||
|
assertFalse(cll.containsNode(46));
|
||||||
|
|
||||||
|
assertTrue(cll.containsNode(1));
|
||||||
|
cll.deleteNode(1);
|
||||||
|
assertFalse(cll.containsNode(1));
|
||||||
|
|
||||||
|
assertTrue(cll.containsNode(13));
|
||||||
|
cll.deleteNode(13);
|
||||||
|
assertFalse(cll.containsNode(13));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenACircularLinkedListWithOneNode_WhenDeletingElement_ThenListDoesNotContainTheElement() {
|
||||||
|
CircularLinkedList cll = new CircularLinkedList();
|
||||||
|
cll.addNode(1);
|
||||||
|
cll.deleteNode(1);
|
||||||
|
assertFalse(cll.containsNode(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private CircularLinkedList createCircularLinkedList() {
|
private CircularLinkedList createCircularLinkedList() {
|
||||||
CircularLinkedList cll = new CircularLinkedList();
|
CircularLinkedList cll = new CircularLinkedList();
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
package com.baeldung.jackson.bidirection;
|
package com.baeldung.jackson.bidirection;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonManagedReference;
|
import com.fasterxml.jackson.annotation.JsonBackReference;
|
||||||
|
|
||||||
public class ItemWithRef {
|
public class ItemWithRef {
|
||||||
public int id;
|
public int id;
|
||||||
public String itemName;
|
public String itemName;
|
||||||
|
|
||||||
@JsonManagedReference
|
@JsonBackReference
|
||||||
public UserWithRef owner;
|
public UserWithRef owner;
|
||||||
|
|
||||||
public ItemWithRef() {
|
public ItemWithRef() {
|
||||||
|
@ -3,13 +3,13 @@ package com.baeldung.jackson.bidirection;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonBackReference;
|
import com.fasterxml.jackson.annotation.JsonManagedReference;
|
||||||
|
|
||||||
public class UserWithRef {
|
public class UserWithRef {
|
||||||
public int id;
|
public int id;
|
||||||
public String name;
|
public String name;
|
||||||
|
|
||||||
@JsonBackReference
|
@JsonManagedReference
|
||||||
public List<ItemWithRef> userItems;
|
public List<ItemWithRef> userItems;
|
||||||
|
|
||||||
public UserWithRef() {
|
public UserWithRef() {
|
||||||
@ -19,7 +19,7 @@ public class UserWithRef {
|
|||||||
public UserWithRef(final int id, final String name) {
|
public UserWithRef(final int id, final String name) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
userItems = new ArrayList<ItemWithRef>();
|
userItems = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addItem(final ItemWithRef item) {
|
public void addItem(final ItemWithRef item) {
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package com.baeldung.jackson.bidirection;
|
package com.baeldung.jackson.bidirection;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.hamcrest.Matchers.not;
|
import static org.hamcrest.Matchers.not;
|
||||||
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
@ -26,16 +28,39 @@ public class JacksonBidirectionRelationUnitTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenBidirectionRelation_whenUsingJacksonReferenceAnnotation_thenCorrect() throws JsonProcessingException {
|
public void givenBidirectionRelation_whenUsingJacksonReferenceAnnotationWithSerialization_thenCorrect() throws JsonProcessingException {
|
||||||
final UserWithRef user = new UserWithRef(1, "John");
|
final UserWithRef user = new UserWithRef(1, "John");
|
||||||
final ItemWithRef item = new ItemWithRef(2, "book", user);
|
final ItemWithRef item = new ItemWithRef(2, "book", user);
|
||||||
user.addItem(item);
|
user.addItem(item);
|
||||||
|
|
||||||
final String result = new ObjectMapper().writeValueAsString(item);
|
final String itemJson = new ObjectMapper().writeValueAsString(item);
|
||||||
|
final String userJson = new ObjectMapper().writeValueAsString(user);
|
||||||
|
|
||||||
assertThat(result, containsString("book"));
|
assertThat(itemJson, containsString("book"));
|
||||||
assertThat(result, containsString("John"));
|
assertThat(itemJson, not(containsString("John")));
|
||||||
assertThat(result, not(containsString("userItems")));
|
|
||||||
|
assertThat(userJson, containsString("John"));
|
||||||
|
assertThat(userJson, containsString("userItems"));
|
||||||
|
assertThat(userJson, containsString("book"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenBidirectionRelation_whenUsingJacksonReferenceAnnotationWithDeserialization_thenCorrect() throws JsonProcessingException {
|
||||||
|
final UserWithRef user = new UserWithRef(1, "John");
|
||||||
|
final ItemWithRef item = new ItemWithRef(2, "book", user);
|
||||||
|
user.addItem(item);
|
||||||
|
|
||||||
|
final String itemJson = new ObjectMapper().writeValueAsString(item);
|
||||||
|
final String userJson = new ObjectMapper().writeValueAsString(user);
|
||||||
|
|
||||||
|
final ItemWithRef itemRead = new ObjectMapper().readValue(itemJson, ItemWithRef.class);
|
||||||
|
final UserWithRef userRead = new ObjectMapper().readValue(userJson, UserWithRef.class);
|
||||||
|
|
||||||
|
assertThat(itemRead.itemName, is("book"));
|
||||||
|
assertThat(itemRead.owner, nullValue());
|
||||||
|
|
||||||
|
assertThat(userRead.name, is("John"));
|
||||||
|
assertThat(userRead.userItems.get(0).itemName, is("book"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -3,3 +3,4 @@
|
|||||||
- [Java Map With Case-Insensitive Keys](https://www.baeldung.com/java-map-with-case-insensitive-keys)
|
- [Java Map With Case-Insensitive Keys](https://www.baeldung.com/java-map-with-case-insensitive-keys)
|
||||||
- [Using a Byte Array as Map Key in Java](https://www.baeldung.com/java-map-key-byte-array)
|
- [Using a Byte Array as Map Key in Java](https://www.baeldung.com/java-map-key-byte-array)
|
||||||
- [Using the Map.Entry Java Class](https://www.baeldung.com/java-map-entry)
|
- [Using the Map.Entry Java Class](https://www.baeldung.com/java-map-entry)
|
||||||
|
- [Optimizing HashMap’s Performance](https://www.baeldung.com/java-hashmap-optimize-performance)
|
||||||
|
@ -52,3 +52,4 @@ Enjoy it :)
|
|||||||
|
|
||||||
- [Intro to Performance Testing using JMeter](https://www.baeldung.com/jmeter)
|
- [Intro to Performance Testing using JMeter](https://www.baeldung.com/jmeter)
|
||||||
- [Configure Jenkins to Run and Show JMeter Tests](https://www.baeldung.com/jenkins-and-jmeter)
|
- [Configure Jenkins to Run and Show JMeter Tests](https://www.baeldung.com/jenkins-and-jmeter)
|
||||||
|
- [Write Extracted Data to a File Using JMeter](https://www.baeldung.com/jmeter-write-to-file)
|
||||||
|
@ -19,6 +19,11 @@
|
|||||||
<artifactId>okhttp</artifactId>
|
<artifactId>okhttp</artifactId>
|
||||||
<version>${okhttp.version}</version>
|
<version>${okhttp.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.okhttp3</groupId>
|
||||||
|
<artifactId>logging-interceptor</artifactId>
|
||||||
|
<version>${okhttp.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
@ -81,9 +86,9 @@
|
|||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<okhttp.version>3.14.2</okhttp.version>
|
<okhttp.version>4.9.1</okhttp.version>
|
||||||
<gson.version>2.8.5</gson.version>
|
<gson.version>2.8.5</gson.version>
|
||||||
<mockwebserver.version>3.14.2</mockwebserver.version>
|
<mockwebserver.version>4.9.1</mockwebserver.version>
|
||||||
<jetty.httpclient.version>1.0.3</jetty.httpclient.version>
|
<jetty.httpclient.version>1.0.3</jetty.httpclient.version>
|
||||||
<jetty.server.version>9.4.19.v20190610</jetty.server.version>
|
<jetty.server.version>9.4.19.v20190610</jetty.server.version>
|
||||||
<rxjava2.version>2.2.11</rxjava2.version>
|
<rxjava2.version>2.2.11</rxjava2.version>
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.baeldung.okhttp.interceptors;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import okhttp3.Interceptor;
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
public class CacheControlResponeInterceptor implements Interceptor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response intercept(Chain chain) throws IOException {
|
||||||
|
Response response = chain.proceed(chain.request());
|
||||||
|
return response.newBuilder()
|
||||||
|
.header("Cache-Control", "no-store")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.baeldung.okhttp.interceptors;
|
||||||
|
|
||||||
|
public class ErrorMessage {
|
||||||
|
|
||||||
|
private final int status;
|
||||||
|
private final String detail;
|
||||||
|
|
||||||
|
public ErrorMessage(int status, String detail) {
|
||||||
|
this.status = status;
|
||||||
|
this.detail = detail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDetail() {
|
||||||
|
return detail;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package com.baeldung.okhttp.interceptors;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
import okhttp3.Interceptor;
|
||||||
|
import okhttp3.MediaType;
|
||||||
|
import okhttp3.Response;
|
||||||
|
import okhttp3.ResponseBody;
|
||||||
|
|
||||||
|
public class ErrorResponseInterceptor implements Interceptor {
|
||||||
|
|
||||||
|
public static final MediaType APPLICATION_JSON = MediaType.get("application/json; charset=utf-8");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response intercept(Chain chain) throws IOException {
|
||||||
|
Response response = chain.proceed(chain.request());
|
||||||
|
|
||||||
|
if(!response.isSuccessful()) {
|
||||||
|
Gson gson = new Gson();
|
||||||
|
String body = gson.toJson(new ErrorMessage(response.code(), "The response from the server was not OK"));
|
||||||
|
ResponseBody responseBody = ResponseBody.create(body, APPLICATION_JSON);
|
||||||
|
|
||||||
|
return response.newBuilder()
|
||||||
|
.body(responseBody)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package com.baeldung.okhttp.interceptors;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import okhttp3.Interceptor;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
public class SimpleLoggingInterceptor implements Interceptor {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(SimpleLoggingInterceptor.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response intercept(Chain chain) throws IOException {
|
||||||
|
Request request = chain.request();
|
||||||
|
|
||||||
|
LOGGER.info("Intercepted headers: {} from URL: {}", request.headers(), request.url());
|
||||||
|
|
||||||
|
return chain.proceed(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,90 @@
|
|||||||
|
package com.baeldung.okhttp.interceptors;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
import okhttp3.logging.HttpLoggingInterceptor;
|
||||||
|
import okhttp3.logging.HttpLoggingInterceptor.Level;
|
||||||
|
import okhttp3.mockwebserver.MockResponse;
|
||||||
|
import okhttp3.mockwebserver.MockWebServer;
|
||||||
|
|
||||||
|
public class InterceptorIntegrationTest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public MockWebServer server = new MockWebServer();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenSimpleLogginInterceptor_whenRequestSent_thenHeadersLogged() throws IOException {
|
||||||
|
server.enqueue(new MockResponse().setBody("Hello Baeldung Readers!"));
|
||||||
|
|
||||||
|
OkHttpClient client = new OkHttpClient.Builder()
|
||||||
|
.addNetworkInterceptor(new SimpleLoggingInterceptor())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(server.url("/greeting"))
|
||||||
|
.header("User-Agent", "A Baeldung Reader")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
try (Response response = client.newCall(request).execute()) {
|
||||||
|
assertEquals("Response code should be: ", 200, response.code());
|
||||||
|
assertEquals("Body should be: ", "Hello Baeldung Readers!", response.body().string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenResponseInterceptor_whenRequestSent_thenCacheControlSetToNoStore() throws IOException {
|
||||||
|
server.enqueue(new MockResponse().setBody("Hello Baeldung Readers!"));
|
||||||
|
|
||||||
|
OkHttpClient client = new OkHttpClient.Builder()
|
||||||
|
.addInterceptor(getHttpLogger())
|
||||||
|
.addInterceptor(new CacheControlResponeInterceptor())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(server.url("/greeting"))
|
||||||
|
.header("User-Agent", "A Baeldung Reader")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
try (Response response = client.newCall(request).execute()) {
|
||||||
|
assertEquals("Response code should be: ", 200, response.code());
|
||||||
|
assertEquals("Body should be: ", "Hello Baeldung Readers!", response.body().string());
|
||||||
|
assertEquals("Response cache-control should be", "no-store", response.header("Cache-Control"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenErrorResponseInterceptor_whenResponseIs500_thenBodyIsJsonWithStatus() throws IOException {
|
||||||
|
server.enqueue(new MockResponse().setResponseCode(500).setBody("Hello Baeldung Readers!"));
|
||||||
|
|
||||||
|
OkHttpClient client = new OkHttpClient.Builder()
|
||||||
|
.addInterceptor(getHttpLogger())
|
||||||
|
.addInterceptor(new ErrorResponseInterceptor())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(server.url("/greeting"))
|
||||||
|
.header("User-Agent", "A Baeldung Reader")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
try (Response response = client.newCall(request).execute()) {
|
||||||
|
assertEquals("Response code should be: ", 500, response.code());
|
||||||
|
assertEquals("Body should be: ", "{\"status\":500,\"detail\":\"The response from the server was not OK\"}",
|
||||||
|
response.body().string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpLoggingInterceptor getHttpLogger() {
|
||||||
|
HttpLoggingInterceptor logger = new HttpLoggingInterceptor();
|
||||||
|
logger.setLevel(Level.HEADERS);
|
||||||
|
return logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -6,7 +6,6 @@ This module contains articles about annotations used in Spring Data JPA
|
|||||||
|
|
||||||
- [DDD Aggregates and @DomainEvents](https://www.baeldung.com/spring-data-ddd)
|
- [DDD Aggregates and @DomainEvents](https://www.baeldung.com/spring-data-ddd)
|
||||||
- [JPA @Embedded And @Embeddable](https://www.baeldung.com/jpa-embedded-embeddable)
|
- [JPA @Embedded And @Embeddable](https://www.baeldung.com/jpa-embedded-embeddable)
|
||||||
- [Spring Data JPA @Modifying Annotation](https://www.baeldung.com/spring-data-jpa-modifying-annotation)
|
|
||||||
- [Spring JPA @Embedded and @EmbeddedId](https://www.baeldung.com/spring-jpa-embedded-method-parameters)
|
- [Spring JPA @Embedded and @EmbeddedId](https://www.baeldung.com/spring-jpa-embedded-method-parameters)
|
||||||
- [Programmatic Transaction Management in Spring](https://www.baeldung.com/spring-programmatic-transaction-management)
|
- [Programmatic Transaction Management in Spring](https://www.baeldung.com/spring-programmatic-transaction-management)
|
||||||
- [JPA Entity Lifecycle Events](https://www.baeldung.com/jpa-entity-lifecycle-events)
|
- [JPA Entity Lifecycle Events](https://www.baeldung.com/jpa-entity-lifecycle-events)
|
||||||
|
@ -12,6 +12,7 @@ This module contains articles about Spring Data JPA used in enterprise applicati
|
|||||||
- [Working with Lazy Element Collections in JPA](https://www.baeldung.com/java-jpa-lazy-collections)
|
- [Working with Lazy Element Collections in JPA](https://www.baeldung.com/java-jpa-lazy-collections)
|
||||||
- [Custom Naming Convention with Spring Data JPA](https://www.baeldung.com/spring-data-jpa-custom-naming)
|
- [Custom Naming Convention with Spring Data JPA](https://www.baeldung.com/spring-data-jpa-custom-naming)
|
||||||
- [Partial Data Update with Spring Data](https://www.baeldung.com/spring-data-partial-update)
|
- [Partial Data Update with Spring Data](https://www.baeldung.com/spring-data-partial-update)
|
||||||
|
- [Spring Data JPA @Modifying Annotation](https://www.baeldung.com/spring-data-jpa-modifying-annotation)
|
||||||
|
|
||||||
### Eclipse Config
|
### Eclipse Config
|
||||||
After importing the project into Eclipse, you may see the following error:
|
After importing the project into Eclipse, you may see the following error:
|
||||||
|
@ -93,6 +93,9 @@ public interface UserRepository extends JpaRepository<User, Integer> , UserRepos
|
|||||||
@Query("delete User u where u.active = false")
|
@Query("delete User u where u.active = false")
|
||||||
int deleteDeactivatedUsers();
|
int deleteDeactivatedUsers();
|
||||||
|
|
||||||
|
@Query("delete User u where u.active = false")
|
||||||
|
int deleteDeactivatedUsersWithNoModifyingAnnotation();
|
||||||
|
|
||||||
@Modifying(clearAutomatically = true, flushAutomatically = true)
|
@Modifying(clearAutomatically = true, flushAutomatically = true)
|
||||||
@Query(value = "alter table USERS add column deleted int(1) not null default 0", nativeQuery = true)
|
@Query(value = "alter table USERS add column deleted int(1) not null default 0", nativeQuery = true)
|
||||||
void addDeletedColumn();
|
void addDeletedColumn();
|
||||||
|
@ -3,6 +3,7 @@ package com.baeldung.boot.daos;
|
|||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
@ -21,6 +22,7 @@ import java.util.function.Predicate;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
public class UserRepositoryCommon {
|
public class UserRepositoryCommon {
|
||||||
@ -520,6 +522,22 @@ public class UserRepositoryCommon {
|
|||||||
assertEquals(1, deletedUsersCount);
|
assertEquals(1, deletedUsersCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Transactional
|
||||||
|
public void givenTwoUsers_whenDeleteDeactivatedUsersWithNoModifyingAnnotation_ThenException() {
|
||||||
|
User usr01 = new User("usr01", LocalDate.of(2018, 1, 1), "usr01@baeldung.com", 1);
|
||||||
|
usr01.setLastLoginDate(LocalDate.now());
|
||||||
|
User usr02 = new User("usr02", LocalDate.of(2018, 6, 1), "usr02@baeldung.com", 0);
|
||||||
|
usr02.setLastLoginDate(LocalDate.of(2018, 7, 20));
|
||||||
|
usr02.setActive(false);
|
||||||
|
|
||||||
|
userRepository.save(usr01);
|
||||||
|
userRepository.save(usr02);
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> userRepository.deleteDeactivatedUsersWithNoModifyingAnnotation())
|
||||||
|
.isInstanceOf(InvalidDataAccessApiUsageException.class);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Transactional
|
@Transactional
|
||||||
public void givenTwoUsers_whenAddDeletedColumn_ThenUsersHaveDeletedColumn() {
|
public void givenTwoUsers_whenAddDeletedColumn_ThenUsersHaveDeletedColumn() {
|
||||||
|
4
pom.xml
4
pom.xml
@ -531,7 +531,7 @@
|
|||||||
<module>protobuffer</module>
|
<module>protobuffer</module>
|
||||||
|
|
||||||
<module>quarkus</module>
|
<module>quarkus</module>
|
||||||
<module>quarkus-extension</module>
|
<!-- <module>quarkus-extension</module> --> <!-- Module broken, fixing in http://team.baeldung.com/browse/JAVA-4770 -->
|
||||||
|
|
||||||
<module>rabbitmq</module>
|
<module>rabbitmq</module>
|
||||||
<!-- <module>raml</module> --> <!-- Not a maven project -->
|
<!-- <module>raml</module> --> <!-- Not a maven project -->
|
||||||
@ -992,7 +992,7 @@
|
|||||||
<module>protobuffer</module>
|
<module>protobuffer</module>
|
||||||
|
|
||||||
<module>quarkus</module>
|
<module>quarkus</module>
|
||||||
<module>quarkus-extension</module>
|
<!-- <module>quarkus-extension</module> --> <!-- Module broken, fixing in http://team.baeldung.com/browse/JAVA-4770 -->
|
||||||
|
|
||||||
<module>rabbitmq</module>
|
<module>rabbitmq</module>
|
||||||
<!-- <module>raml</module> --> <!-- Not a maven project -->
|
<!-- <module>raml</module> --> <!-- Not a maven project -->
|
||||||
|
@ -5,4 +5,4 @@ This module contains articles about Spring Boot: JAX-RS vs Spring
|
|||||||
|
|
||||||
### Relevant Articles:
|
### Relevant Articles:
|
||||||
|
|
||||||
- [REST API: JAX-RS vs Spring](https://www.baeldung.com/TBD)
|
- [REST API: JAX-RS vs Spring](https://www.baeldung.com/rest-api-jax-rs-vs-spring)
|
||||||
|
@ -1,3 +1 @@
|
|||||||
server.port=8888
|
server.port=8888
|
||||||
spring.security.user.name=root
|
|
||||||
spring.security.user.password=docker!
|
|
||||||
|
@ -1,3 +1 @@
|
|||||||
server.port=9999
|
server.port=9999
|
||||||
spring.security.user.name=root
|
|
||||||
spring.security.user.password=docker!
|
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
<module>spring-security-legacy-oidc</module>
|
<module>spring-security-legacy-oidc</module>
|
||||||
<module>spring-security-oidc</module>
|
<module>spring-security-oidc</module>
|
||||||
<module>spring-security-okta</module>
|
<module>spring-security-okta</module>
|
||||||
|
<module>spring-security-saml</module>
|
||||||
<module>spring-security-web-react</module>
|
<module>spring-security-web-react</module>
|
||||||
<module>spring-security-web-rest</module>
|
<module>spring-security-web-rest</module>
|
||||||
<module>spring-security-web-rest-basic-auth</module>
|
<module>spring-security-web-rest-basic-auth</module>
|
||||||
|
73
spring-security-modules/spring-security-saml/pom.xml
Normal file
73
spring-security-modules/spring-security-saml/pom.xml
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<?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/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>spring-security-saml</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<name>spring-security-saml</name>
|
||||||
|
<packaging>war</packaging>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.baeldung</groupId>
|
||||||
|
<artifactId>parent-boot-2</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<relativePath>../../parent-boot-2</relativePath>
|
||||||
|
</parent>
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>Shibboleth</id>
|
||||||
|
<name>Shibboleth</name>
|
||||||
|
<url>https://build.shibboleth.net/nexus/content/repositories/releases/</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</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-thymeleaf</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security.extensions</groupId>
|
||||||
|
<artifactId>spring-security-saml2-core</artifactId>
|
||||||
|
<version>${saml2-core.spring.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<finalName>spring-security-saml</finalName>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<addResources>true</addResources>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>repackage</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<saml2-core.spring.version>1.0.10.RELEASE</saml2-core.spring.version>
|
||||||
|
</properties>
|
||||||
|
</project>
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.baeldung.saml;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class Application {
|
||||||
|
public static void main(String... args) {
|
||||||
|
SpringApplication.run(Application.class, args);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.baeldung.saml.authentication;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.providers.ExpiringUsernameAuthenticationToken;
|
||||||
|
import org.springframework.security.saml.SAMLAuthenticationProvider;
|
||||||
|
import org.springframework.security.saml.SAMLCredential;
|
||||||
|
|
||||||
|
public class CustomSAMLAuthenticationProvider extends SAMLAuthenticationProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<? extends GrantedAuthority> getEntitlements(SAMLCredential credential, Object userDetail) {
|
||||||
|
|
||||||
|
if(userDetail instanceof ExpiringUsernameAuthenticationToken) {
|
||||||
|
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
|
||||||
|
authorities.addAll(((ExpiringUsernameAuthenticationToken) userDetail).getAuthorities());
|
||||||
|
return authorities;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,226 @@
|
|||||||
|
package com.baeldung.saml.config;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider;
|
||||||
|
import org.opensaml.saml2.metadata.provider.MetadataProvider;
|
||||||
|
import org.opensaml.saml2.metadata.provider.MetadataProviderException;
|
||||||
|
import org.opensaml.util.resource.ResourceException;
|
||||||
|
import org.opensaml.xml.parse.StaticBasicParserPool;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.io.DefaultResourceLoader;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.security.saml.*;
|
||||||
|
import org.springframework.security.saml.context.SAMLContextProviderImpl;
|
||||||
|
import org.springframework.security.saml.key.JKSKeyManager;
|
||||||
|
import org.springframework.security.saml.key.KeyManager;
|
||||||
|
import org.springframework.security.saml.log.SAMLDefaultLogger;
|
||||||
|
import org.springframework.security.saml.metadata.CachingMetadataManager;
|
||||||
|
import org.springframework.security.saml.metadata.ExtendedMetadata;
|
||||||
|
import org.springframework.security.saml.metadata.ExtendedMetadataDelegate;
|
||||||
|
import org.springframework.security.saml.processor.*;
|
||||||
|
import org.springframework.security.saml.util.VelocityFactory;
|
||||||
|
import org.springframework.security.saml.websso.*;
|
||||||
|
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
|
||||||
|
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
||||||
|
import org.springframework.security.web.authentication.logout.LogoutHandler;
|
||||||
|
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
|
||||||
|
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
|
||||||
|
|
||||||
|
import com.baeldung.saml.authentication.CustomSAMLAuthenticationProvider;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class SamlSecurityConfig {
|
||||||
|
|
||||||
|
@Value("${saml.keystore.location}")
|
||||||
|
private String samlKeystoreLocation;
|
||||||
|
|
||||||
|
@Value("${saml.keystore.password}")
|
||||||
|
private String samlKeystorePassword;
|
||||||
|
|
||||||
|
@Value("${saml.keystore.alias}")
|
||||||
|
private String samlKeystoreAlias;
|
||||||
|
|
||||||
|
@Value("${saml.idp}")
|
||||||
|
private String defaultIdp;
|
||||||
|
|
||||||
|
@Bean(initMethod = "initialize")
|
||||||
|
public StaticBasicParserPool parserPool() {
|
||||||
|
return new StaticBasicParserPool();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SAMLAuthenticationProvider samlAuthenticationProvider() {
|
||||||
|
return new CustomSAMLAuthenticationProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SAMLContextProviderImpl contextProvider() {
|
||||||
|
return new SAMLContextProviderImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public static SAMLBootstrap samlBootstrap() {
|
||||||
|
return new SAMLBootstrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SAMLDefaultLogger samlLogger() {
|
||||||
|
return new SAMLDefaultLogger();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public WebSSOProfileConsumer webSSOprofileConsumer() {
|
||||||
|
return new WebSSOProfileConsumerImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Qualifier("hokWebSSOprofileConsumer")
|
||||||
|
public WebSSOProfileConsumerHoKImpl hokWebSSOProfileConsumer() {
|
||||||
|
return new WebSSOProfileConsumerHoKImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public WebSSOProfile webSSOprofile() {
|
||||||
|
return new WebSSOProfileImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public WebSSOProfileConsumerHoKImpl hokWebSSOProfile() {
|
||||||
|
return new WebSSOProfileConsumerHoKImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public WebSSOProfileECPImpl ecpProfile() {
|
||||||
|
return new WebSSOProfileECPImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SingleLogoutProfile logoutProfile() {
|
||||||
|
return new SingleLogoutProfileImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public KeyManager keyManager() {
|
||||||
|
DefaultResourceLoader loader = new DefaultResourceLoader();
|
||||||
|
Resource storeFile = loader.getResource(samlKeystoreLocation);
|
||||||
|
Map<String, String> passwords = new HashMap<>();
|
||||||
|
passwords.put(samlKeystoreAlias, samlKeystorePassword);
|
||||||
|
return new JKSKeyManager(storeFile, samlKeystorePassword, passwords, samlKeystoreAlias);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public WebSSOProfileOptions defaultWebSSOProfileOptions() {
|
||||||
|
WebSSOProfileOptions webSSOProfileOptions = new WebSSOProfileOptions();
|
||||||
|
webSSOProfileOptions.setIncludeScoping(false);
|
||||||
|
return webSSOProfileOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SAMLEntryPoint samlEntryPoint() {
|
||||||
|
SAMLEntryPoint samlEntryPoint = new SAMLEntryPoint();
|
||||||
|
samlEntryPoint.setDefaultProfileOptions(defaultWebSSOProfileOptions());
|
||||||
|
return samlEntryPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ExtendedMetadata extendedMetadata() {
|
||||||
|
ExtendedMetadata extendedMetadata = new ExtendedMetadata();
|
||||||
|
extendedMetadata.setIdpDiscoveryEnabled(false);
|
||||||
|
extendedMetadata.setSignMetadata(false);
|
||||||
|
return extendedMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Qualifier("okta")
|
||||||
|
public ExtendedMetadataDelegate oktaExtendedMetadataProvider() throws MetadataProviderException {
|
||||||
|
File metadata = null;
|
||||||
|
try {
|
||||||
|
metadata = new File("./src/main/resources/saml/metadata/sso.xml");
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
FilesystemMetadataProvider provider = new FilesystemMetadataProvider(metadata);
|
||||||
|
provider.setParserPool(parserPool());
|
||||||
|
return new ExtendedMetadataDelegate(provider, extendedMetadata());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Qualifier("metadata")
|
||||||
|
public CachingMetadataManager metadata() throws MetadataProviderException, ResourceException {
|
||||||
|
List<MetadataProvider> providers = new ArrayList<>();
|
||||||
|
providers.add(oktaExtendedMetadataProvider());
|
||||||
|
CachingMetadataManager metadataManager = new CachingMetadataManager(providers);
|
||||||
|
metadataManager.setDefaultIDP(defaultIdp);
|
||||||
|
return metadataManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Qualifier("saml")
|
||||||
|
public SavedRequestAwareAuthenticationSuccessHandler successRedirectHandler() {
|
||||||
|
SavedRequestAwareAuthenticationSuccessHandler successRedirectHandler = new SavedRequestAwareAuthenticationSuccessHandler();
|
||||||
|
successRedirectHandler.setDefaultTargetUrl("/home");
|
||||||
|
return successRedirectHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Qualifier("saml")
|
||||||
|
public SimpleUrlAuthenticationFailureHandler authenticationFailureHandler() {
|
||||||
|
SimpleUrlAuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();
|
||||||
|
failureHandler.setUseForward(true);
|
||||||
|
failureHandler.setDefaultFailureUrl("/error");
|
||||||
|
return failureHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SimpleUrlLogoutSuccessHandler successLogoutHandler() {
|
||||||
|
SimpleUrlLogoutSuccessHandler successLogoutHandler = new SimpleUrlLogoutSuccessHandler();
|
||||||
|
successLogoutHandler.setDefaultTargetUrl("/");
|
||||||
|
return successLogoutHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SecurityContextLogoutHandler logoutHandler() {
|
||||||
|
SecurityContextLogoutHandler logoutHandler = new SecurityContextLogoutHandler();
|
||||||
|
logoutHandler.setInvalidateHttpSession(true);
|
||||||
|
logoutHandler.setClearAuthentication(true);
|
||||||
|
return logoutHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SAMLLogoutProcessingFilter samlLogoutProcessingFilter() {
|
||||||
|
return new SAMLLogoutProcessingFilter(successLogoutHandler(), logoutHandler());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SAMLLogoutFilter samlLogoutFilter() {
|
||||||
|
return new SAMLLogoutFilter(successLogoutHandler(),
|
||||||
|
new LogoutHandler[] { logoutHandler() },
|
||||||
|
new LogoutHandler[] { logoutHandler() });
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public HTTPPostBinding httpPostBinding() {
|
||||||
|
return new HTTPPostBinding(parserPool(), VelocityFactory.getEngine());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public HTTPRedirectDeflateBinding httpRedirectDeflateBinding() {
|
||||||
|
return new HTTPRedirectDeflateBinding(parserPool());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SAMLProcessorImpl processor() {
|
||||||
|
ArrayList<SAMLBinding> bindings = new ArrayList<>();
|
||||||
|
bindings.add(httpRedirectDeflateBinding());
|
||||||
|
bindings.add(httpPostBinding());
|
||||||
|
return new SAMLProcessorImpl(bindings);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,152 @@
|
|||||||
|
package com.baeldung.saml.config;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||||
|
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||||
|
import org.springframework.security.saml.*;
|
||||||
|
import org.springframework.security.saml.key.KeyManager;
|
||||||
|
import org.springframework.security.saml.metadata.*;
|
||||||
|
import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||||
|
import org.springframework.security.web.FilterChainProxy;
|
||||||
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
|
||||||
|
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
|
||||||
|
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
||||||
|
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||||
|
import org.springframework.security.web.csrf.CsrfFilter;
|
||||||
|
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
@EnableGlobalMethodSecurity(securedEnabled = true)
|
||||||
|
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
|
@Value("${saml.sp}")
|
||||||
|
private String samlAudience;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("saml")
|
||||||
|
private SavedRequestAwareAuthenticationSuccessHandler samlAuthSuccessHandler;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("saml")
|
||||||
|
private SimpleUrlAuthenticationFailureHandler samlAuthFailureHandler;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SAMLEntryPoint samlEntryPoint;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SAMLLogoutFilter samlLogoutFilter;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SAMLLogoutProcessingFilter samlLogoutProcessingFilter;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SAMLDiscovery samlDiscovery() {
|
||||||
|
SAMLDiscovery idpDiscovery = new SAMLDiscovery();
|
||||||
|
return idpDiscovery;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SAMLAuthenticationProvider samlAuthenticationProvider;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ExtendedMetadata extendedMetadata;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private KeyManager keyManager;
|
||||||
|
|
||||||
|
public MetadataGenerator metadataGenerator() {
|
||||||
|
MetadataGenerator metadataGenerator = new MetadataGenerator();
|
||||||
|
metadataGenerator.setEntityId(samlAudience);
|
||||||
|
metadataGenerator.setExtendedMetadata(extendedMetadata);
|
||||||
|
metadataGenerator.setIncludeDiscoveryExtension(false);
|
||||||
|
metadataGenerator.setKeyManager(keyManager);
|
||||||
|
return metadataGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SAMLProcessingFilter samlWebSSOProcessingFilter() throws Exception {
|
||||||
|
SAMLProcessingFilter samlWebSSOProcessingFilter = new SAMLProcessingFilter();
|
||||||
|
samlWebSSOProcessingFilter.setAuthenticationManager(authenticationManager());
|
||||||
|
samlWebSSOProcessingFilter.setAuthenticationSuccessHandler(samlAuthSuccessHandler);
|
||||||
|
samlWebSSOProcessingFilter.setAuthenticationFailureHandler(samlAuthFailureHandler);
|
||||||
|
return samlWebSSOProcessingFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public FilterChainProxy samlFilter() throws Exception {
|
||||||
|
List<SecurityFilterChain> chains = new ArrayList<>();
|
||||||
|
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/SSO/**"),
|
||||||
|
samlWebSSOProcessingFilter()));
|
||||||
|
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/discovery/**"),
|
||||||
|
samlDiscovery()));
|
||||||
|
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/login/**"),
|
||||||
|
samlEntryPoint));
|
||||||
|
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/logout/**"),
|
||||||
|
samlLogoutFilter));
|
||||||
|
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/SingleLogout/**"),
|
||||||
|
samlLogoutProcessingFilter));
|
||||||
|
return new FilterChainProxy(chains);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Override
|
||||||
|
public AuthenticationManager authenticationManagerBean() throws Exception {
|
||||||
|
return super.authenticationManagerBean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public MetadataGeneratorFilter metadataGeneratorFilter() {
|
||||||
|
return new MetadataGeneratorFilter(metadataGenerator());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
|
http
|
||||||
|
.csrf()
|
||||||
|
.disable();
|
||||||
|
|
||||||
|
http
|
||||||
|
.httpBasic()
|
||||||
|
.authenticationEntryPoint(samlEntryPoint);
|
||||||
|
|
||||||
|
http
|
||||||
|
.addFilterBefore(metadataGeneratorFilter(), ChannelProcessingFilter.class)
|
||||||
|
.addFilterAfter(samlFilter(), BasicAuthenticationFilter.class)
|
||||||
|
.addFilterBefore(samlFilter(), CsrfFilter.class);
|
||||||
|
|
||||||
|
http
|
||||||
|
.authorizeRequests()
|
||||||
|
.antMatchers("/").permitAll()
|
||||||
|
.anyRequest().authenticated();
|
||||||
|
|
||||||
|
http
|
||||||
|
.logout()
|
||||||
|
.addLogoutHandler((request, response, authentication) -> {
|
||||||
|
try {
|
||||||
|
response.sendRedirect("/saml/logout");
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||||
|
auth.authenticationProvider(samlAuthenticationProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package com.baeldung.saml.controller;
|
||||||
|
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public class HomeController {
|
||||||
|
|
||||||
|
@RequestMapping("/")
|
||||||
|
public String index() {
|
||||||
|
return "index";
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(value = "/auth")
|
||||||
|
public String handleSamlAuth() {
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
if (auth != null) {
|
||||||
|
return "redirect:/home";
|
||||||
|
} else {
|
||||||
|
return "/";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping("/home")
|
||||||
|
public String home(Model model) {
|
||||||
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
model.addAttribute("username", authentication.getPrincipal());
|
||||||
|
return "home";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
saml.keystore.location=classpath:/saml/samlKeystore.jks
|
||||||
|
saml.keystore.password=<key_pass>
|
||||||
|
saml.keystore.alias=<key_alias>
|
||||||
|
|
||||||
|
saml.idp=<idp_issuer_url>
|
||||||
|
saml.sp=http://localhost:8080/saml/metadata
|
@ -0,0 +1,44 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<md:EntityDescriptor
|
||||||
|
entityID="http://www.okta.com/exk26fxqrz8LLk9dV4x7"
|
||||||
|
xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata">
|
||||||
|
<md:IDPSSODescriptor
|
||||||
|
WantAuthnRequestsSigned="false"
|
||||||
|
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
|
||||||
|
<md:KeyDescriptor use="signing">
|
||||||
|
<ds:KeyInfo
|
||||||
|
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
|
||||||
|
<ds:X509Data>
|
||||||
|
<ds:X509Certificate>MIIDpDCCAoygAwIBAgIGAXGiSQ7ZMA0GCSqGSIb3DQEBCwUAMIGSMQswCQYDVQQGEwJVUzETMBEG
|
||||||
|
A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEU
|
||||||
|
MBIGA1UECwwLU1NPUHJvdmlkZXIxEzARBgNVBAMMCmRldi05MjY2NjYxHDAaBgkqhkiG9w0BCQEW
|
||||||
|
DWluZm9Ab2t0YS5jb20wHhcNMjAwNDIyMTQyNjA5WhcNMzAwNDIyMTQyNzA5WjCBkjELMAkGA1UE
|
||||||
|
BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTALBgNV
|
||||||
|
BAoMBE9rdGExFDASBgNVBAsMC1NTT1Byb3ZpZGVyMRMwEQYDVQQDDApkZXYtOTI2NjY2MRwwGgYJ
|
||||||
|
KoZIhvcNAQkBFg1pbmZvQG9rdGEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
|
||||||
|
g1rQYYqeVx2gl/UUnLJzp5hrm06VOILJB9hIUmNqXgWV3UjzDq/zX0KW8MENjsO7+S8a+LLnYRkb
|
||||||
|
N5egH9FSt8AHtB1pmfXDtpUQmWe9yJbNxbCISoc6XzCmaRw3HRv9pK5SciIutciz9lvFaHMWAWtP
|
||||||
|
MmQSKdhMet52tuf6sTy4ODeXjyMnD9q5QOKww1SJ678wjHbGRRhNvCxvTSAH33sa4oNCf2RvP9hp
|
||||||
|
NiJRcYW9yLZXmZArPQOuAx5PIXfHhK2e4ac39YO4fgO7gwU5TZ+vL7o6iEmd9tk44PrND0ZV5yzZ
|
||||||
|
+Y33Hiun3fIiZu/nZZGUjm4k4exl8JJpwrVTHQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBcfHcL
|
||||||
|
2DjTjZGoANF4dPpGXTYdVnL/XzGiLS+3LR/HDrEz/EqsHouF40RnzdZ7Ax7RReKBYCUUqHpSE+LU
|
||||||
|
ductz2ANguzyseGEn72I4Ym4ytQWnFyTXeW+xI9CoCLGfOUhT1hlKjsu/qNM8qwKFPWkzQp7mDN8
|
||||||
|
S9MGhsnbiyeD/lceAEKw16Os73/sX2j7F+43WVCYRDCRB8pRIPfcqYLXUIUSstQlwEvCF7HyeO4+
|
||||||
|
jxKHA1tp9Cpmj7/VD9TE3fyvrbVmfjTbKjF7/0wYQNfbHDDko0ratDMAizG5/d3i9wk9KbGCHSxT
|
||||||
|
ph5nl1pdjKgAYPK0iNDnGCZbGKzXOrqV
|
||||||
|
</ds:X509Certificate>
|
||||||
|
</ds:X509Data>
|
||||||
|
</ds:KeyInfo>
|
||||||
|
</md:KeyDescriptor>
|
||||||
|
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
|
||||||
|
</md:NameIDFormat>
|
||||||
|
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
|
||||||
|
</md:NameIDFormat>
|
||||||
|
<md:SingleSignOnService
|
||||||
|
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
|
||||||
|
Location="https://dev-926666.okta.com/app/dev-926666_baeldungspringsecuritysaml_1/exk26fxqrz8LLk9dV4x7/sso/saml" />
|
||||||
|
<md:SingleSignOnService
|
||||||
|
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
|
||||||
|
Location="https://dev-926666.okta.com/app/dev-926666_baeldungspringsecuritysaml_1/exk26fxqrz8LLk9dV4x7/sso/saml" />
|
||||||
|
</md:IDPSSODescriptor>
|
||||||
|
</md:EntityDescriptor>
|
Binary file not shown.
@ -0,0 +1,13 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<h6 class="border-bottom border-gray pb-2 mb-0">Something went wrong</h6>
|
||||||
|
<div class="media text-muted pt-3">
|
||||||
|
<i class="fas fa-door-closed fa-2x fa-fw mr-2 spring-green" data-fa-transform="shrink-4"></i>
|
||||||
|
<p class="media-body pb-3 mb-0 small lh-125 border-bottom border-gray">
|
||||||
|
An error occurred
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
</html>
|
@ -0,0 +1,13 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Baeldung Spring Security SAML: Home</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h3><Strong>Welcome!</strong><br/>You are successfully logged in!</h3>
|
||||||
|
<p>You are logged as <span class="badge badge-dark" th:text="${username}">null</span>.</p>
|
||||||
|
<small>
|
||||||
|
<a th:href="@{/logout}">Logout</a>
|
||||||
|
</small>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,10 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Baeldung Spring Security SAML</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h3><Strong>Welcome to Baeldung Spring Security SAML</strong></h3>
|
||||||
|
<a th:href="@{/auth}">Login</a>
|
||||||
|
</body>
|
||||||
|
</html>
|
3
testing-modules/zerocode/README.md
Normal file
3
testing-modules/zerocode/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
### Relevant Articles:
|
||||||
|
|
||||||
|
- [Introduction to ZeroCode](https://www.baeldung.com/zerocode-intro)
|
Loading…
x
Reference in New Issue
Block a user