Merge branch 'eugenp:master' into master

This commit is contained in:
Ulisses Lima 2022-03-11 20:06:39 -03:00 committed by GitHub
commit 3b043a30dc
33 changed files with 1244 additions and 87 deletions

View File

@ -0,0 +1,43 @@
package com.baeldung.lockbykey;
/**
* This class shows examples of how you should use the lock
*
*/
public class ExampleUsage {
void doWithSimpleExclusiveLock(String key) {
SimpleExclusiveLockByKey simpleExclusiveLockByKey = new SimpleExclusiveLockByKey();
if (simpleExclusiveLockByKey.tryLock(key)) {
try {
// do stuff
} finally {
// it is very important to unlock in the finally block to avoid locking keys forever
simpleExclusiveLockByKey.unlock(key);
}
}
}
// A concrete example can be found in the unit tests
void doWithLock(String key) {
LockByKey lockByKey = new LockByKey();
lockByKey.lock(key);
try {
// do stuff
} finally {
lockByKey.unlock(key);
}
}
// It works exactly the same as with locks
void doWithSemaphore(String key) {
SimultaneousEntriesLockByKey lockByKey = new SimultaneousEntriesLockByKey();
lockByKey.lock(key);
try {
// do stuff
} finally {
lockByKey.unlock(key);
}
}
}

View File

@ -0,0 +1,41 @@
package com.baeldung.lockbykey;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockByKey {
private static class LockWrapper {
private final Lock lock = new ReentrantLock();
private final AtomicInteger numberOfThreadsInQueue = new AtomicInteger(1);
private LockWrapper addThreadInQueue() {
numberOfThreadsInQueue.incrementAndGet();
return this;
}
private int removeThreadFromQueue() {
return numberOfThreadsInQueue.decrementAndGet();
}
}
private static ConcurrentHashMap<String, LockWrapper> locks = new ConcurrentHashMap<String, LockWrapper>();
public void lock(String key) {
LockWrapper lockWrapper = locks.compute(key, (k, v) -> v == null ? new LockWrapper() : v.addThreadInQueue());
lockWrapper.lock.lock();
}
public void unlock(String key) {
LockWrapper lockWrapper = locks.get(key);
lockWrapper.lock.unlock();
if (lockWrapper.removeThreadFromQueue() == 0) {
// NB : We pass in the specific value to remove to handle the case where another thread would queue right before the removal
locks.remove(key, lockWrapper);
}
}
}

View File

@ -0,0 +1,18 @@
package com.baeldung.lockbykey;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public class SimpleExclusiveLockByKey {
private static Set<String> usedKeys= ConcurrentHashMap.newKeySet();
public boolean tryLock(String key) {
return usedKeys.add(key);
}
public void unlock(String key) {
usedKeys.remove(key);
}
}

View File

@ -0,0 +1,25 @@
package com.baeldung.lockbykey;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Semaphore;
public class SimultaneousEntriesLockByKey {
private static final int ALLOWED_THREADS = 2;
private static ConcurrentHashMap<String, Semaphore> semaphores = new ConcurrentHashMap<String, Semaphore>();
public void lock(String key) {
Semaphore semaphore = semaphores.compute(key, (k, v) -> v == null ? new Semaphore(ALLOWED_THREADS) : v);
semaphore.acquireUninterruptibly();
}
public void unlock(String key) {
Semaphore semaphore = semaphores.get(key);
semaphore.release();
if (semaphore.availablePermits() == ALLOWED_THREADS) {
semaphores.remove(key, semaphore);
}
}
}

View File

@ -0,0 +1,106 @@
package com.baeldung.lockbykey;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.jupiter.api.Test;
public class LockByKeyUnitTest {
@Test
void givenNoLockedKey_WhenLock_ThenSuccess() throws InterruptedException {
AtomicBoolean threadWasExecuted = new AtomicBoolean(false);
Thread thread = new Thread(() -> {
String key = "key";
LockByKey lockByKey = new LockByKey();
lockByKey.lock(key);
try {
threadWasExecuted.set(true);
} finally {
lockByKey.unlock(key);
}
});
try {
thread.start();
Thread.sleep(100);
} finally {
assertTrue(threadWasExecuted.get());
}
}
@Test
void givenLockedKey_WhenLock_ThenFailure() throws InterruptedException {
String key = "key";
LockByKey lockByKey = new LockByKey();
lockByKey.lock(key);
AtomicBoolean anotherThreadWasExecuted = new AtomicBoolean(false);
Thread threadLockingOnAnotherKey = new Thread(() -> {
LockByKey otherLockByKey = new LockByKey();
otherLockByKey.lock(key);
try {
anotherThreadWasExecuted.set(true);
} finally {
otherLockByKey.unlock(key);
}
});
try {
threadLockingOnAnotherKey.start();
Thread.sleep(100);
} finally {
assertFalse(anotherThreadWasExecuted.get());
lockByKey.unlock(key);
}
}
@Test
void givenAnotherKeyLocked_WhenLock_ThenSuccess() throws InterruptedException {
String key = "key";
LockByKey lockByKey = new LockByKey();
lockByKey.lock(key);
AtomicBoolean anotherThreadWasExecuted = new AtomicBoolean(false);
Thread threadLockingOnAnotherKey = new Thread(() -> {
String anotherKey = "anotherKey";
LockByKey otherLockByKey = new LockByKey();
otherLockByKey.lock(anotherKey);
try {
anotherThreadWasExecuted.set(true);
} finally {
otherLockByKey.unlock(anotherKey);
}
});
try {
threadLockingOnAnotherKey.start();
Thread.sleep(100);
} finally {
assertTrue(anotherThreadWasExecuted.get());
lockByKey.unlock(key);
}
}
@Test
void givenUnlockedKey_WhenLock_ThenSuccess() throws InterruptedException {
String key = "key";
LockByKey lockByKey = new LockByKey();
lockByKey.lock(key);
AtomicBoolean anotherThreadWasExecuted = new AtomicBoolean(false);
Thread threadLockingOnAnotherKey = new Thread(() -> {
LockByKey otherLockByKey = new LockByKey();
otherLockByKey.lock(key);
try {
anotherThreadWasExecuted.set(true);
} finally {
otherLockByKey.unlock(key);
}
});
try {
lockByKey.unlock(key);
threadLockingOnAnotherKey.start();
Thread.sleep(100);
} finally {
assertTrue(anotherThreadWasExecuted.get());
}
}
}

View File

@ -0,0 +1,51 @@
package com.baeldung.lockbykey;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.lang.reflect.Field;
import java.util.concurrent.ConcurrentHashMap;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class SimpleExclusiveLockByKeyUnitTest {
@BeforeEach
void cleanUpLocks() throws Exception {
Field field = SimpleExclusiveLockByKey.class.getDeclaredField("usedKeys");
field.setAccessible(true);
field.set(null, ConcurrentHashMap.newKeySet());
}
@Test
void givenNoLockedKey_WhenTryLock_ThenSuccess() {
SimpleExclusiveLockByKey lockByKey = new SimpleExclusiveLockByKey();
assertTrue(lockByKey.tryLock("key"));
}
@Test
void givenLockedKey_WhenTryLock_ThenFailure() {
String key = "key";
SimpleExclusiveLockByKey lockByKey = new SimpleExclusiveLockByKey();
lockByKey.tryLock(key);
assertFalse(lockByKey.tryLock(key));
}
@Test
void givenAnotherKeyLocked_WhenTryLock_ThenSuccess() {
SimpleExclusiveLockByKey lockByKey = new SimpleExclusiveLockByKey();
lockByKey.tryLock("other");
assertTrue(lockByKey.tryLock("key"));
}
@Test
void givenUnlockedKey_WhenTryLock_ThenSuccess() {
String key = "key";
SimpleExclusiveLockByKey lockByKey = new SimpleExclusiveLockByKey();
lockByKey.tryLock(key);
lockByKey.unlock(key);
assertTrue(lockByKey.tryLock(key));
}
}

View File

@ -0,0 +1,146 @@
package com.baeldung.lockbykey;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.jupiter.api.Test;
public class SimultaneousEntriesLockByKeyUnitTest {
@Test
void givenNoKeyUsed_WhenLock_ThenSuccess() throws InterruptedException {
AtomicBoolean threadWasExecuted = new AtomicBoolean(false);
Thread thread = new Thread(() -> {
String key = "key";
SimultaneousEntriesLockByKey lockByKey = new SimultaneousEntriesLockByKey();
lockByKey.lock(key);
try {
threadWasExecuted.set(true);
} finally {
lockByKey.unlock(key);
}
});
try {
thread.start();
Thread.sleep(100);
} finally {
assertTrue(threadWasExecuted.get());
}
}
@Test
void givenKeyLockedWithRemainingPermits_WhenLock_ThenSuccess() throws InterruptedException {
String key = "key";
SimultaneousEntriesLockByKey lockByKey = new SimultaneousEntriesLockByKey();
lockByKey.lock(key);
AtomicBoolean anotherThreadWasExecuted = new AtomicBoolean(false);
Thread threadLockingOnAnotherKey = new Thread(() -> {
SimultaneousEntriesLockByKey otherLockByKeyWithSemaphore = new SimultaneousEntriesLockByKey();
otherLockByKeyWithSemaphore.lock(key);
try {
anotherThreadWasExecuted.set(true);
} finally {
otherLockByKeyWithSemaphore.unlock(key);
}
});
try {
threadLockingOnAnotherKey.start();
Thread.sleep(100);
} finally {
assertTrue(anotherThreadWasExecuted.get());
lockByKey.unlock(key);
}
}
@Test
void givenKeyLockedWithNoRemainingPermits_WhenLock_ThenFailure() throws InterruptedException {
String key = "key";
SimultaneousEntriesLockByKey lockByKey = new SimultaneousEntriesLockByKey();
lockByKey.lock(key);
AtomicBoolean anotherThreadWasExecuted = new AtomicBoolean(false);
Thread threadLockingOnAnotherKey1 = new Thread(() -> {
SimultaneousEntriesLockByKey otherLockByKeyWithSemaphore = new SimultaneousEntriesLockByKey();
otherLockByKeyWithSemaphore.lock(key);
try {
Thread.sleep(200); // make sure this thread will release the lock after the assertion
} catch (InterruptedException e) {
} finally {
otherLockByKeyWithSemaphore.unlock(key);
}
});
Thread threadLockingOnAnotherKey2 = new Thread(() -> {
SimultaneousEntriesLockByKey otherLockByKey = new SimultaneousEntriesLockByKey();
try {
Thread.sleep(50); // make sure thread1 will acquire the key first
} catch (InterruptedException e) {
}
otherLockByKey.lock(key);
try {
anotherThreadWasExecuted.set(true);
} finally {
otherLockByKey.unlock(key);
}
});
try {
threadLockingOnAnotherKey1.start();
threadLockingOnAnotherKey2.start();
Thread.sleep(100);
} finally {
assertFalse(anotherThreadWasExecuted.get());
lockByKey.unlock(key);
}
}
@Test
void givenAnotherKeyLocked_WhenLock_ThenSuccess() throws InterruptedException {
String key = "key";
SimultaneousEntriesLockByKey lockByKey = new SimultaneousEntriesLockByKey();
lockByKey.lock(key);
AtomicBoolean anotherThreadWasExecuted = new AtomicBoolean(false);
Thread threadLockingOnAnotherKey = new Thread(() -> {
String anotherKey = "anotherKey";
SimultaneousEntriesLockByKey otherLockByKey = new SimultaneousEntriesLockByKey();
otherLockByKey.lock(anotherKey);
try {
anotherThreadWasExecuted.set(true);
} finally {
otherLockByKey.unlock(anotherKey);
}
});
try {
threadLockingOnAnotherKey.start();
Thread.sleep(100);
} finally {
assertTrue(anotherThreadWasExecuted.get());
lockByKey.unlock(key);
}
}
@Test
void givenUnlockedKey_WhenLock_ThenSuccess() throws InterruptedException {
String key = "key";
SimultaneousEntriesLockByKey lockByKey = new SimultaneousEntriesLockByKey();
lockByKey.lock(key);
AtomicBoolean anotherThreadWasExecuted = new AtomicBoolean(false);
Thread threadLockingOnAnotherKey = new Thread(() -> {
SimultaneousEntriesLockByKey otherLockByKey = new SimultaneousEntriesLockByKey();
otherLockByKey.lock(key);
try {
anotherThreadWasExecuted.set(true);
} finally {
otherLockByKey.unlock(key);
}
});
try {
lockByKey.unlock(key);
threadLockingOnAnotherKey.start();
Thread.sleep(100);
} finally {
assertTrue(anotherThreadWasExecuted.get());
}
}
}

View File

@ -19,6 +19,7 @@
<module>maven-copy-files</module>
<module>maven-custom-plugin</module>
<module>maven-exec-plugin</module>
<!-- <module>maven-generate-war</module> --> <!-- We haven't upgraded to java 11. -->
<module>maven-integration-test</module>
<module>maven-multi-source</module>
<module>maven-plugins</module>

View File

@ -3,7 +3,7 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>hibernate-mapping-2y</artifactId>
<artifactId>hibernate-mapping-2</artifactId>
<version>0.1-SNAPSHOT</version>
<name>hibernate-mapping-2</name>

View File

@ -45,6 +45,13 @@ public class HibernateManyToManyAnnotationJavaConfigMainIntegrationTest {
projects.add(new Project("Networking Project"));
session.persist(new Employee("Peter", "Oven", projects));
session.persist(new Employee("Allan", "Norman", projects));
Set<Employee> employees = new HashSet<Employee>();
employees.add(new Employee("Sam", "Curran"));
employees.add(new Employee("Tom", "Curran"));
Project project = new Project("Database Project");
project.setEmployees(employees);
session.persist(project);
}
}

View File

@ -1,7 +1,7 @@
package com.baeldung.hibernate.manytomany;
import static junit.framework.TestCase.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.HashSet;
import java.util.List;
@ -23,60 +23,73 @@ import com.baeldung.manytomany.util.HibernateUtil;
* Configured in: manytomany.cfg.xml
*/
public class HibernateManyToManyAnnotationMainIntegrationTest {
private static SessionFactory sessionFactory;
private static SessionFactory sessionFactory;
private Session session;
private Session session;
@BeforeClass
public static void beforeTests() {
sessionFactory = HibernateUtil.getSessionFactory();
}
@BeforeClass
public static void beforeTests() {
sessionFactory = HibernateUtil.getSessionFactory();
}
@Before
public void setUp() {
session = sessionFactory.openSession();
session.beginTransaction();
}
@Before
public void setUp() {
session = sessionFactory.openSession();
session.beginTransaction();
}
@Test
public void givenData_whenInsert_thenCreatesMtoMrelationship() {
String[] employeeData = { "Peter Oven", "Allan Norman" };
String[] projectData = { "IT Project", "Networking Project" };
Set<Project> projects = new HashSet<Project>();
for (String proj : projectData) {
projects.add(new Project(proj));
}
for (String emp : employeeData) {
Employee employee = new Employee(emp.split(" ")[0], emp.split(" ")[1]);
assertEquals(0, employee.getProjects().size());
employee.setProjects(projects);
session.persist(employee);
assertNotNull(employee);
}
}
@Test
@Test
public void givenSession_whenRead_thenReturnsMtoMdata() {
prepareData();
@SuppressWarnings("unchecked")
List<Employee> employeeList = session.createQuery("FROM Employee").list();
@SuppressWarnings("unchecked")
List<Employee> employeeList = session.createQuery("FROM Employee").list();
List<Project> projectList = session.createQuery("FROM Project").list();
assertNotNull(employeeList);
assertNotNull(projectList);
assertEquals(2, employeeList.size());
assertEquals(2, projectList.size());
for(Employee employee : employeeList) {
assertNotNull(employee.getProjects());
assertEquals(2, employee.getProjects().size());
}
for(Project project : projectList) {
assertNotNull(project.getEmployees());
assertEquals(2, project.getEmployees().size());
}
}
@After
public void tearDown() {
session.getTransaction()
.commit();
session.close();
}
private void prepareData() {
String[] employeeData = { "Peter Oven", "Allan Norman" };
String[] projectData = { "IT Project", "Networking Project" };
Set<Project> projects = new HashSet<Project>();
@AfterClass
public static void afterTests() {
sessionFactory.close();
}
for (String proj : projectData) {
projects.add(new Project(proj));
}
for (String emp : employeeData) {
Employee employee = new Employee(emp.split(" ")[0], emp.split(" ")[1]);
employee.setProjects(projects);
for (Project proj : projects) {
proj.getEmployees().add(employee);
}
session.persist(employee);
}
}
@After
public void tearDown() {
session.getTransaction().commit();
session.close();
}
@AfterClass
public static void afterTests() {
sessionFactory.close();
}
}

View File

@ -0,0 +1,99 @@
package com.baeldung.mongo;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.bson.Document;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Updates;
import com.mongodb.client.result.UpdateResult;
public class PushOperations {
private static MongoClient mongoClient;
private static String testCollectionName;
private static String databaseName;
public static void setUp() {
if (mongoClient == null) {
mongoClient = new MongoClient("localhost", 27017);
}
databaseName = "baeldung";
testCollectionName = "orders";
}
public static void pushOperationUsingDBObject() {
MongoDatabase database = mongoClient.getDatabase(databaseName);
MongoCollection<Document> collection = database.getCollection(testCollectionName);
DBObject listItem = new BasicDBObject("items", new BasicDBObject("itemName", "PIZZA MANIA").append("quantity", 1)
.append("price", 800));
BasicDBObject searchFilter = new BasicDBObject("customerId", 1023);
BasicDBObject updateQuery = new BasicDBObject();
updateQuery.append("$push", listItem);
UpdateResult updateResult = collection.updateOne(searchFilter, updateQuery);
System.out.println("updateResult:- " + updateResult);
}
public static void pushOperationUsingDocument() {
MongoDatabase database = mongoClient.getDatabase(databaseName);
MongoCollection<Document> collection = database.getCollection(testCollectionName);
Document item = new Document().append("itemName", "PIZZA MANIA")
.append("quantity", 1)
.append("price", 800);
UpdateResult updateResult = collection.updateOne(Filters.eq("customerId", 1023), Updates.push("items", item));
System.out.println("updateResult:- " + updateResult);
}
public static void addToSetOperation() {
MongoDatabase database = mongoClient.getDatabase(databaseName);
MongoCollection<Document> collection = database.getCollection(testCollectionName);
Document item = new Document().append("itemName", "PIZZA MANIA")
.append("quantity", 1)
.append("price", 800);
UpdateResult updateResult = collection.updateOne(Filters.eq("customerId", 1023), Updates.addToSet("items", item));
System.out.println("updateResult:- " + updateResult);
}
public static void main(String args[]) {
//
// Connect to cluster (default is localhost:27017)
//
setUp();
//
// Push document into the array using DBObject
//
pushOperationUsingDBObject();
//
// Push document into the array using Document.
//
pushOperationUsingDocument();
//
// Push document into the array using addToSet operator.
//
addToSetOperation();
}
}

View File

@ -0,0 +1,92 @@
package com.baeldung.mongo;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import org.bson.Document;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Updates;
import com.mongodb.client.result.UpdateResult;
public class PushOperationLiveTest {
private static MongoClient mongoClient;
private static MongoDatabase db;
private static MongoCollection<Document> collection;
@BeforeClass
public static void setup() {
if (mongoClient == null) {
mongoClient = new MongoClient("localhost", 27017);
db = mongoClient.getDatabase("baeldung");
collection = db.getCollection("orders");
collection.insertOne(
Document.parse("{\n" + " \"customerId\": 1023,\n" + " \"orderTimestamp\": NumberLong(\"1646460073000\"),\n" + " \"shippingDestination\": \"336, Street No.1 Pawai Mumbai\",\n" + " \"purchaseOrder\": 1000,\n"
+ " \"contactNumber\":\"9898987676\",\n" + " \"items\": [ \n" + " {\n" + " \"itemName\": \"BERGER\",\n" + " \"quantity\": 1,\n" + " \"price\": 500\n" + " },\n"
+ " {\n" + " \"itemName\": \"VEG PIZZA\",\n" + " \"quantity\": 1,\n" + " \"price\": 800\n" + " } \n" + " ]\n" + " }"));
}
}
@Test
public void givenOrderCollection_whenPushOperationUsingDBObject_thenCheckingForDocument() {
DBObject listItem = new BasicDBObject("items", new BasicDBObject("itemName", "PIZZA MANIA").append("quantity", 1)
.append("price", 800));
BasicDBObject searchFilter = new BasicDBObject("customerId", 1023);
BasicDBObject updateQuery = new BasicDBObject();
updateQuery.append("$push", listItem);
UpdateResult updateResult = collection.updateOne(searchFilter, updateQuery);
Document orderDetail = collection.find(Filters.eq("customerId", 1023))
.first();
assertNotNull(orderDetail);
assertFalse(orderDetail.isEmpty());
}
@Test
public void givenOrderCollection_whenPushOperationUsingDocument_thenCheckingForDocument() {
Document item = new Document().append("itemName", "PIZZA MANIA")
.append("quantity", 1)
.append("price", 800);
UpdateResult updateResult = collection.updateOne(Filters.eq("customerId", 1023), Updates.push("items", item));
Document orderDetail = collection.find(Filters.eq("customerId", 1023))
.first();
assertNotNull(orderDetail);
assertFalse(orderDetail.isEmpty());
}
@Test
public void givenOrderCollection_whenAddToSetOperation_thenCheckingForDocument() {
Document item = new Document().append("itemName", "PIZZA MANIA")
.append("quantity", 1)
.append("price", 800);
UpdateResult updateResult = collection.updateOne(Filters.eq("customerId", 1023), Updates.addToSet("items", item));
Document orderDetail = collection.find(Filters.eq("customerId", 1023))
.first();
assertNotNull(orderDetail);
assertFalse(orderDetail.isEmpty());
}
@AfterClass
public static void cleanUp() {
mongoClient.close();
}
}

View File

@ -27,6 +27,7 @@
<module>hbase</module>
<module>hibernate5</module>
<module>hibernate-mapping</module> <!-- long running -->
<module>hibernate-mapping-2</module>
<module>hibernate-ogm</module>
<module>hibernate-annotations</module>
<module>hibernate-exceptions</module>
@ -73,6 +74,7 @@
<module>spring-data-jpa-crud</module>
<module>spring-data-jpa-crud-2</module>
<module>spring-data-jpa-enterprise</module>
<module>spring-data-jpa-enterprise-2</module>
<module>spring-data-jpa-filtering</module>
<module>spring-data-jpa-query</module>
<module>spring-data-jpa-query-2</module>

89
pom.xml
View File

@ -7,9 +7,6 @@
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
<modules>
<module>spring-5-webflux-2</module>
</modules>
<name>parent-modules</name>
<packaging>pom</packaging>
@ -355,6 +352,7 @@
<module>apache-libraries</module>
<module>apache-olingo</module>
<module>apache-poi</module>
<module>apache-poi-2</module>
<module>apache-rocketmq</module>
<module>apache-shiro</module>
<module>apache-spark</module>
@ -653,6 +651,7 @@
<module>spring-cucumber</module>
<module>spring-data-rest</module>
<module>spring-data-rest-2</module>
<module>spring-data-rest-querydsl</module>
<module>spring-di</module>
<module>spring-di-2</module>
@ -841,6 +840,7 @@
<module>apache-libraries</module>
<module>apache-olingo</module>
<module>apache-poi</module>
<module>apache-poi-2</module>
<module>apache-rocketmq</module>
<module>apache-shiro</module>
<module>apache-spark</module>
@ -855,6 +855,7 @@
<module>atomix</module>
<module>aws</module>
<module>aws-app-sync</module>
<module>aws-lambda</module>
<module>aws-reactive</module>
@ -906,6 +907,7 @@
<!-- <module>gradle-6</module> --> <!-- Not a maven project -->
<!-- <module>grails</module> --> <!-- Not a maven project -->
<module>graphql/graphql-java</module>
<module>graphql/graphql-dgs</module>
<module>grpc</module>
<module>gson</module>
<module>guava-modules</module>
@ -967,6 +969,7 @@
<module>ksqldb</module>
<!-- <module>lagom</module> --> <!-- Not a maven project -->
<module>language-interop</module>
<module>libraries-2</module>
<module>libraries-3</module>
@ -981,6 +984,7 @@
<module>libraries-http-2</module>
<module>libraries-io</module>
<module>libraries-primitive</module>
<module>libraries-rpc</module>
<module>libraries-security</module>
<module>libraries-server</module>
<module>libraries-server-2</module>
@ -1096,6 +1100,7 @@
<module>spring-5-reactive-oauth</module>
<module>spring-5-reactive-security</module>
<module>spring-5-webflux</module>
<module>spring-5-webflux-2</module>
<module>spring-reactive</module>
<module>spring-activiti</module>
@ -1128,9 +1133,11 @@
<module>spring-cucumber</module>
<module>spring-data-rest</module>
<module>spring-data-rest-2</module>
<module>spring-data-rest-querydsl</module>
<module>spring-di</module>
<module>spring-di-2</module>
<module>spring-di-3</module>
<module>spring-drools</module>
<module>spring-ejb</module>
@ -1168,6 +1175,8 @@
<module>spring-static-resources</module>
<module>spring-swagger-codegen</module>
<module>spring-threads</module>
<module>spring-vault</module>
<module>spring-vertx</module>
@ -1317,39 +1326,43 @@
<module>core-java-modules/core-java-9-improvements</module>
<module>core-java-modules/core-java-9-jigsaw</module>
<!-- <module>core-java-modules/core-java-9-new-features</module> --> <!-- uses preview features, to be decided how to handle -->
<module>core-java-modules/core-java-9-streams</module>
<module>core-java-modules/core-java-10</module>
<module>core-java-modules/core-java-11</module>
<module>core-java-modules/core-java-11-2</module>
<!-- <module>core-java-modules/core-java-12</module> --> <!-- uses preview features, to be decided how to handle -->
<!-- <module>core-java-modules/core-java-13</module> --> <!-- uses preview features, to be decided how to handle -->
<!-- <module>core-java-modules/core-java-14</module> --> <!-- uses preview features, to be decided how to handle -->
<!-- <module>core-java-modules/core-java-15</module> --> <!-- uses preview features, to be decided how to handle -->
<module>core-java-modules/core-java-collections-set</module>
<module>core-java-modules/core-java-collections-maps-4</module>
<module>core-java-modules/core-java-date-operations-1</module>
<module>core-java-modules/core-java-datetime-conversion</module>
<module>core-java-modules/core-java-datetime-string</module>
<module>core-java-modules/core-java-io-conversions-2</module>
<module>core-java-modules/core-java-jpms</module>
<module>core-java-modules/core-java-os</module>
<module>core-java-modules/core-java-string-algorithms-3</module>
<module>core-java-modules/core-java-string-operations-3</module>
<module>core-java-modules/core-java-string-operations-4</module>
<module>core-java-modules/core-java-time-measurements</module>
<module>core-java-modules/core-java-networking-3</module>
<module>core-java-modules/multimodulemavenproject</module>
<module>ddd-modules</module>
<module>httpclient-2</module>
<module>libraries-concurrency</module>
<module>persistence-modules/sirix</module>
<module>persistence-modules/spring-data-cassandra-2</module>
<module>quarkus-vs-springboot</module>
<module>quarkus-jandex</module>
<module>spring-boot-modules/spring-boot-cassandre</module>
<module>spring-boot-modules/spring-boot-camel</module>
<module>testing-modules/testing-assertions</module>
<module>persistence-modules/fauna</module>
<module>core-java-modules/core-java-9-streams</module>
<module>core-java-modules/core-java-10</module>
<module>core-java-modules/core-java-11</module>
<module>core-java-modules/core-java-11-2</module>
<!-- <module>core-java-modules/core-java-12</module> --> <!-- uses preview features, to be decided how to handle -->
<!-- <module>core-java-modules/core-java-13</module> --> <!-- uses preview features, to be decided how to handle -->
<!-- <module>core-java-modules/core-java-14</module> --> <!-- uses preview features, to be decided how to handle -->
<!-- <module>core-java-modules/core-java-15</module> --> <!-- uses preview features, to be decided how to handle -->
<!-- <module>core-java-modules/core-java-16</module> --> <!-- uses preview features, to be decided how to handle -->
<!-- <module>core-java-modules/core-java-17</module> --> <!-- uses preview features, to be decided how to handle -->
<module>core-java-modules/core-java-collections-set</module>
<module>core-java-modules/core-java-collections-maps-4</module>
<module>core-java-modules/core-java-date-operations-1</module>
<module>core-java-modules/core-java-datetime-conversion</module>
<module>core-java-modules/core-java-datetime-string</module>
<module>core-java-modules/core-java-io-conversions-2</module>
<module>core-java-modules/core-java-jpms</module>
<module>core-java-modules/core-java-os</module>
<module>core-java-modules/core-java-string-algorithms-3</module>
<module>core-java-modules/core-java-string-operations-3</module>
<module>core-java-modules/core-java-string-operations-4</module>
<module>core-java-modules/core-java-time-measurements</module>
<module>core-java-modules/core-java-networking-3</module>
<module>core-java-modules/multimodulemavenproject</module>
<module>core-java-modules/core-java-strings</module>
<module>ddd-modules</module>
<module>docker</module>
<module>httpclient-2</module>
<module>libraries-concurrency</module>
<module>persistence-modules/sirix</module>
<module>persistence-modules/spring-data-cassandra-2</module>
<module>quarkus-vs-springboot</module>
<module>quarkus-jandex</module>
<module>spring-boot-modules/spring-boot-cassandre</module>
<module>spring-boot-modules/spring-boot-camel</module>
<module>testing-modules/testing-assertions</module>
<module>persistence-modules/fauna</module>
</modules>
</profile>
@ -1388,6 +1401,8 @@
<!-- <module>core-java-modules/core-java-13</module> --> <!-- uses preview features, to be decided how to handle -->
<!-- <module>core-java-modules/core-java-14</module> --> <!-- uses preview features, to be decided how to handle -->
<!-- <module>core-java-modules/core-java-15</module> --> <!-- uses preview features, to be decided how to handle -->
<!-- <module>core-java-modules/core-java-16</module> --> <!-- uses preview features, to be decided how to handle -->
<!-- <module>core-java-modules/core-java-17</module> --> <!-- uses preview features, to be decided how to handle -->
<module>core-java-modules/core-java-collections-set</module>
<module>core-java-modules/core-java-collections-maps-4</module>
<module>core-java-modules/core-java-date-operations-1</module>
@ -1396,6 +1411,7 @@
<module>core-java-modules/core-java-io-conversions-2</module>
<module>core-java-modules/core-java-jpms</module>
<module>core-java-modules/core-java-os</module>
<module>core-java-modules/core-java-string-algorithms-3</module>
<module>core-java-modules/core-java-string-operations-3</module>
<module>core-java-modules/core-java-string-operations-4</module>
<module>core-java-modules/core-java-time-measurements</module>
@ -1403,6 +1419,7 @@
<module>core-java-modules/multimodulemavenproject</module>
<module>core-java-modules/core-java-strings</module>
<module>ddd-modules</module>
<module>docker</module>
<module>httpclient-2</module>
<module>libraries-concurrency</module>
<module>persistence-modules/sirix</module>

View File

@ -0,0 +1,14 @@
package com.baeldung.keycloak;
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class KeycloakConfig {
@Bean
public KeycloakSpringBootConfigResolver keycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
}

View File

@ -23,11 +23,6 @@ class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
auth.authenticationProvider(keycloakAuthenticationProvider);
}
@Bean
public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
// Specifies the session authentication strategy
@Bean
@Override

View File

@ -45,9 +45,11 @@
<module>spring-cloud-ribbon-retry</module>
<module>spring-cloud-circuit-breaker</module>
<module>spring-cloud-eureka-self-preservation</module>
<!--<module>spring-cloud-openfeign</module> --> <!-- Fixing in JAVA-2820 -->
<!-- <module>spring-cloud-openfeign</module> --> <!-- Fixing under JAVA-10446 -->
<!-- <module>spring-cloud-netflix-feign</module> --> <!-- Fixing under JAVA-10431 -->
<module>spring-cloud-sentinel</module>
<module>spring-cloud-dapr</module>
<module>spring-cloud-docker</module>
</modules>
<build>

View File

@ -21,6 +21,7 @@
<module>wildfly-jpa</module>
<module>wildfly-ejb-interfaces</module>
<module>wildfly-ejb</module>
<module>wildfly-mdb</module>
</modules>
<dependencyManagement>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-security-web-boot-3</artifactId>
<version>0.0.1-SNAPSHOT</version>
@ -23,6 +24,15 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>

View File

@ -0,0 +1,18 @@
package com.baeldung.mongoauth;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;
import com.baeldung.mongoauth.config.MongoConfig;
import com.baeldung.mongoauth.config.SecurityConfig;
@SpringBootApplication
@Import({ SecurityConfig.class, MongoConfig.class })
public class MongoAuthApplication {
public static void main(String... args) {
SpringApplication.run(MongoAuthApplication.class, args);
}
}

View File

@ -0,0 +1,40 @@
package com.baeldung.mongoauth.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.util.SocketUtils;
import com.mongodb.client.MongoClients;
import de.flapdoodle.embed.mongo.MongodExecutable;
import de.flapdoodle.embed.mongo.MongodStarter;
import de.flapdoodle.embed.mongo.config.ImmutableMongodConfig;
import de.flapdoodle.embed.mongo.config.MongodConfig;
import de.flapdoodle.embed.mongo.config.Net;
import de.flapdoodle.embed.mongo.distribution.Version;
import de.flapdoodle.embed.process.runtime.Network;
@Configuration
public class MongoConfig {
private static final String CONNECTION_STRING = "mongodb://%s:%d";
private static final String HOST = "localhost";
@Bean
public MongoTemplate mongoTemplate() throws Exception {
int randomPort = SocketUtils.findAvailableTcpPort();
ImmutableMongodConfig mongoDbConfig = MongodConfig.builder()
.version(Version.Main.PRODUCTION)
.net(new Net(HOST, randomPort, Network.localhostIsIPv6()))
.build();
MongodStarter starter = MongodStarter.getDefaultInstance();
MongodExecutable mongodExecutable = starter.prepare(mongoDbConfig);
mongodExecutable.start();
return new MongoTemplate(MongoClients.create(String.format(CONNECTION_STRING, HOST, randomPort)), "mongo_auth");
}
}

View File

@ -0,0 +1,59 @@
package com.baeldung.mongoauth.config;
import org.springframework.beans.factory.annotation.Autowired;
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.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, jsr250Enabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final UserDetailsService userDetailsService;
public SecurityConfig(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
@Bean
public AuthenticationManager customAuthenticationManager() throws Exception {
return authenticationManager();
}
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(@Autowired AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(bCryptPasswordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.authorizeRequests()
.and()
.httpBasic()
.and()
.authorizeRequests()
.anyRequest()
.permitAll()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}

View File

@ -0,0 +1,23 @@
package com.baeldung.mongoauth.controller;
import javax.annotation.security.RolesAllowed;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ResourceController {
@RolesAllowed("ROLE_ADMIN")
@GetMapping("/admin")
public String admin() {
return "Hello Admin!";
}
@RolesAllowed({ "ROLE_ADMIN", "ROLE_USER" })
@GetMapping("/user")
public String user() {
return "Hello User!";
}
}

View File

@ -0,0 +1,13 @@
package com.baeldung.mongoauth.domain;
public class Role {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@ -0,0 +1,83 @@
package com.baeldung.mongoauth.domain;
import java.util.Objects;
import java.util.Set;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.MongoId;
import org.springframework.security.core.userdetails.UserDetails;
@Document
public class User implements UserDetails {
private @MongoId ObjectId id;
private String username;
private String password;
private Set<UserRole> userRoles;
public ObjectId getId() {
return id;
}
@Override
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public void setUserRoles(Set<UserRole> userRoles) {
this.userRoles = userRoles;
}
@Override
public Set<UserRole> getAuthorities() {
return this.userRoles;
}
@Override
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public boolean isAccountNonExpired() {
return false;
}
@Override
public boolean isAccountNonLocked() {
return false;
}
@Override
public boolean isCredentialsNonExpired() {
return false;
}
@Override
public boolean isEnabled() {
return false;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
User user = (User) o;
return Objects.equals(username, user.username);
}
@Override
public int hashCode() {
return Objects.hash(username);
}
}

View File

@ -0,0 +1,21 @@
package com.baeldung.mongoauth.domain;
import org.springframework.security.core.GrantedAuthority;
public class UserRole implements GrantedAuthority {
private Role role;
@Override
public String getAuthority() {
return role.getName();
}
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
}

View File

@ -0,0 +1,13 @@
package com.baeldung.mongoauth.repository;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;
import com.baeldung.mongoauth.domain.User;
public interface UserRepository extends MongoRepository<User, String> {
@Query("{username:'?0'}")
User findUserByUsername(String username);
}

View File

@ -0,0 +1,41 @@
package com.baeldung.mongoauth.service;
import java.util.HashSet;
import java.util.Set;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.baeldung.mongoauth.repository.UserRepository;
@Service
public class MongoAuthUserDetailService implements UserDetailsService {
private final UserRepository userRepository;
public MongoAuthUserDetailService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
com.baeldung.mongoauth.domain.User user = userRepository.findUserByUsername(userName);
Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
user.getAuthorities()
.forEach(role -> {
grantedAuthorities.add(new SimpleGrantedAuthority(role.getRole()
.getName()));
});
return new User(user.getUsername(), user.getPassword(), grantedAuthorities);
}
}

View File

@ -0,0 +1,5 @@
package com.baeldung.mongoauth.service;
public interface SecurityService {
boolean login(String username, String password);
}

View File

@ -0,0 +1,39 @@
package com.baeldung.mongoauth.service;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;
@Service
public class SecurityServiceImpl implements SecurityService {
private final AuthenticationManager authenticationManager;
private final UserDetailsService userDetailsService;
public SecurityServiceImpl(AuthenticationManager authenticationManager, UserDetailsService userDetailsService) {
this.authenticationManager = authenticationManager;
this.userDetailsService = userDetailsService;
}
@Override
public boolean login(String username, String password) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
authenticationManager.authenticate(usernamePasswordAuthenticationToken);
if (usernamePasswordAuthenticationToken.isAuthenticated()) {
SecurityContextHolder.getContext()
.setAuthentication(usernamePasswordAuthenticationToken);
return true;
}
return false;
}
}

View File

@ -0,0 +1 @@
spring.mongodb.embedded.version=4.4.9

View File

@ -0,0 +1,118 @@
package com.baeldung.mongoauth;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.Collections;
import java.util.HashSet;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import com.baeldung.mongoauth.domain.Role;
import com.baeldung.mongoauth.domain.User;
import com.baeldung.mongoauth.domain.UserRole;
@SpringBootTest(classes = { MongoAuthApplication.class })
@AutoConfigureMockMvc
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
class MongoAuthApplicationIntegrationTest {
@Autowired
private WebApplicationContext context;
@Autowired
private MongoTemplate mongoTemplate;
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
private MockMvc mvc;
private static final String USER_NAME = "user@gmail.com";
private static final String ADMIN_NAME = "admin@gmail.com";
private static final String PASSWORD = "password";
@BeforeEach
public void setup() {
setUp();
mvc = MockMvcBuilders.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
private void setUp() {
Role roleUser = new Role();
roleUser.setName("ROLE_USER");
mongoTemplate.save(roleUser);
User user = new User();
user.setUsername(USER_NAME);
user.setPassword(bCryptPasswordEncoder.encode(PASSWORD));
UserRole userRole = new UserRole();
userRole.setRole(roleUser);
user.setUserRoles(new HashSet<>(Collections.singletonList(userRole)));
mongoTemplate.save(user);
User admin = new User();
admin.setUsername(ADMIN_NAME);
admin.setPassword(bCryptPasswordEncoder.encode(PASSWORD));
Role roleAdmin = new Role();
roleAdmin.setName("ROLE_ADMIN");
mongoTemplate.save(roleAdmin);
UserRole adminRole = new UserRole();
adminRole.setRole(roleAdmin);
admin.setUserRoles(new HashSet<>(Collections.singletonList(adminRole)));
mongoTemplate.save(admin);
}
@Test
void givenUserCredentials_whenInvokeUserAuthorizedEndPoint_thenReturn200() throws Exception {
mvc.perform(get("/user").with(httpBasic(USER_NAME, PASSWORD)))
.andExpect(status().isOk());
}
@Test
void givenUserNotExists_whenInvokeEndPoint_thenReturn401() throws Exception {
mvc.perform(get("/user").with(httpBasic("not_existing_user", "password")))
.andExpect(status().isUnauthorized());
}
@Test
void givenUserExistsAndWrongPassword_whenInvokeEndPoint_thenReturn401() throws Exception {
mvc.perform(get("/user").with(httpBasic(USER_NAME, "wrong_password")))
.andExpect(status().isUnauthorized());
}
@Test
void givenUserCredentials_whenInvokeAdminAuthorizedEndPoint_thenReturn403() throws Exception {
mvc.perform(get("/admin").with(httpBasic(USER_NAME, PASSWORD)))
.andExpect(status().isForbidden());
}
@Test
void givenAdminCredentials_whenInvokeAdminAuthorizedEndPoint_thenReturn200() throws Exception {
mvc.perform(get("/admin").with(httpBasic(ADMIN_NAME, PASSWORD)))
.andExpect(status().isOk());
mvc.perform(get("/user").with(httpBasic(ADMIN_NAME, PASSWORD)))
.andExpect(status().isOk());
}
}