Merge remote-tracking branch 'eugenp/master'
This commit is contained in:
commit
0d0e3dabc5
|
@ -0,0 +1,44 @@
|
|||
package com.baeldung.spliteratorAPI;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Article {
|
||||
private List<Author> listOfAuthors;
|
||||
private int id;
|
||||
private String name;
|
||||
|
||||
public Article(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Article(List<Author> listOfAuthors, int id) {
|
||||
super();
|
||||
this.listOfAuthors = listOfAuthors;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public List<Author> getListOfAuthors() {
|
||||
return listOfAuthors;
|
||||
}
|
||||
|
||||
public void setListOfAuthors(List<Author> listOfAuthors) {
|
||||
this.listOfAuthors = listOfAuthors;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.baeldung.spliteratorAPI;
|
||||
|
||||
public class Author {
|
||||
private String name;
|
||||
private int relatedArticleId;
|
||||
|
||||
public Author(String name, int relatedArticleId) {
|
||||
this.name = name;
|
||||
this.relatedArticleId = relatedArticleId;
|
||||
}
|
||||
|
||||
public int getRelatedArticleId() {
|
||||
return relatedArticleId;
|
||||
}
|
||||
|
||||
public void setRelatedArticleId(int relatedArticleId) {
|
||||
this.relatedArticleId = relatedArticleId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[name: " + name + ", relatedId: " + relatedArticleId + "]";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package com.baeldung.spliteratorAPI;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Spliterator;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
public class Executor {
|
||||
public void executeCustomSpliterator() {
|
||||
Article article = new Article(Arrays.asList(new Author("Ahmad", 0), new Author("Eugen", 0), new Author("Alice", 1), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1),
|
||||
new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0),
|
||||
new Author("Alice", 1), new Author("Mike", 0), new Author("Michał", 0), new Author("Loredana", 1)), 0);
|
||||
Stream<Author> stream = IntStream.range(0, article.getListOfAuthors()
|
||||
.size())
|
||||
.mapToObj(article.getListOfAuthors()::get);
|
||||
System.out.println("count= " + countAutors(stream.parallel()));
|
||||
Spliterator<Author> spliterator = new RelatedAuthorSpliterator(article.getListOfAuthors());
|
||||
Stream<Author> stream2 = StreamSupport.stream(spliterator, true);
|
||||
System.out.println("count= " + countAutors(stream2.parallel()));
|
||||
}
|
||||
|
||||
public void executeSpliterator() {
|
||||
Spliterator<Article> split1 = generateElements().spliterator();
|
||||
Spliterator<Article> split2 = split1.trySplit();
|
||||
ExecutorService service = Executors.newCachedThreadPool();
|
||||
service.execute(new Task(split1));
|
||||
service.execute(new Task(split2));
|
||||
}
|
||||
|
||||
private static int countAutors(Stream<Author> stream) {
|
||||
RelatedAuthorCounter wordCounter = stream.reduce(new RelatedAuthorCounter(0, true), RelatedAuthorCounter::accumulate, RelatedAuthorCounter::combine);
|
||||
return wordCounter.getCounter();
|
||||
}
|
||||
|
||||
private List<Article> generateElements() {
|
||||
return Stream.generate(() -> new Article("Java"))
|
||||
.limit(35000)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.baeldung.spliteratorAPI;
|
||||
|
||||
public class RelatedAuthorCounter {
|
||||
private final int counter;
|
||||
private final boolean isRelated;
|
||||
|
||||
public RelatedAuthorCounter(int counter, boolean isRelated) {
|
||||
this.counter = counter;
|
||||
this.isRelated = isRelated;
|
||||
}
|
||||
|
||||
public RelatedAuthorCounter accumulate(Author author) {
|
||||
if (author.getRelatedArticleId() == 0) {
|
||||
return isRelated ? this : new RelatedAuthorCounter(counter, true);
|
||||
} else {
|
||||
return isRelated ? new RelatedAuthorCounter(counter + 1, false) : this;
|
||||
}
|
||||
}
|
||||
|
||||
public RelatedAuthorCounter combine(RelatedAuthorCounter RelatedAuthorCounter) {
|
||||
return new RelatedAuthorCounter(counter + RelatedAuthorCounter.counter, RelatedAuthorCounter.isRelated);
|
||||
}
|
||||
|
||||
public int getCounter() {
|
||||
return counter;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package com.baeldung.spliteratorAPI;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Spliterator;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class RelatedAuthorSpliterator implements Spliterator<Author> {
|
||||
private final List<Author> list;
|
||||
private int current = 0;
|
||||
|
||||
public RelatedAuthorSpliterator(List<Author> list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryAdvance(Consumer<? super Author> action) {
|
||||
action.accept(list.get(current++));
|
||||
return current < list.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spliterator<Author> trySplit() {
|
||||
int currentSize = list.size() - current;
|
||||
if (currentSize < 10) {
|
||||
return null;
|
||||
}
|
||||
for (int splitPos = currentSize / 2 + current; splitPos < list.size(); splitPos++) {
|
||||
if (list.get(splitPos)
|
||||
.getRelatedArticleId() == 0) {
|
||||
Spliterator<Author> spliterator = new RelatedAuthorSpliterator(list.subList(current, splitPos));
|
||||
current = splitPos;
|
||||
return spliterator;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long estimateSize() {
|
||||
return list.size() - current;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int characteristics() {
|
||||
return SIZED + CONCURRENT;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.baeldung.spliteratorAPI;
|
||||
|
||||
import java.util.Spliterator;
|
||||
|
||||
public class Task implements Runnable {
|
||||
private Spliterator<Article> spliterator;
|
||||
private final static String SUFFIX = "- published by Baeldung";
|
||||
|
||||
public Task(Spliterator<Article> spliterator) {
|
||||
this.spliterator = spliterator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
int current = 0;
|
||||
while (spliterator.tryAdvance(article -> {
|
||||
article.setName(article.getName()
|
||||
.concat(SUFFIX));
|
||||
})) {
|
||||
current++;
|
||||
}
|
||||
;
|
||||
System.out.println(Thread.currentThread()
|
||||
.getName() + ":" + current);
|
||||
}
|
||||
}
|
|
@ -43,8 +43,9 @@ public class ControlSubThread implements Runnable {
|
|||
try {
|
||||
Thread.sleep(interval);
|
||||
} catch (InterruptedException e) {
|
||||
// no-op, just loop again
|
||||
}
|
||||
Thread.currentThread().interrupt();
|
||||
System.out.println("Thread was interrupted, Failed to complete operation");
|
||||
}
|
||||
// do something
|
||||
}
|
||||
stopped.set(true);
|
||||
|
|
|
@ -44,6 +44,11 @@
|
|||
<artifactId>kotlin-stdlib</artifactId>
|
||||
<version>${kotlin-stdlib.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib-jre8</artifactId>
|
||||
<version>${kotlin-stdlib.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-test-junit</artifactId>
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
package com.baeldung.kotlin
|
||||
|
||||
import org.junit.Test
|
||||
import java.beans.ExceptionListener
|
||||
import java.beans.XMLEncoder
|
||||
import java.io.*
|
||||
import java.lang.Exception
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.test.fail
|
||||
|
||||
class UseTest {
|
||||
|
||||
@Test
|
||||
fun givenCloseable_whenUseIsCalled_thenItIsClosed() {
|
||||
val stringWriter = StringWriter()
|
||||
val writer = BufferedWriter(stringWriter) //Using a BufferedWriter because after close() it throws.
|
||||
writer.use {
|
||||
assertEquals(writer, it)
|
||||
|
||||
it.write("something")
|
||||
}
|
||||
try {
|
||||
writer.write("something else")
|
||||
|
||||
fail("write() should have thrown an exception because the writer is closed.")
|
||||
} catch (e: IOException) {
|
||||
//Ok
|
||||
}
|
||||
|
||||
assertEquals("something", stringWriter.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenAutoCloseable_whenUseIsCalled_thenItIsClosed() {
|
||||
val baos = ByteArrayOutputStream()
|
||||
val encoder = XMLEncoder(PrintStream(baos)) //XMLEncoder is AutoCloseable but not Closeable.
|
||||
//Here, we use a PrintStream because after close() it throws.
|
||||
encoder.exceptionListener = ThrowingExceptionListener()
|
||||
encoder.use {
|
||||
assertEquals(encoder, it)
|
||||
|
||||
it.writeObject("something")
|
||||
}
|
||||
try {
|
||||
encoder.writeObject("something else")
|
||||
encoder.flush()
|
||||
|
||||
fail("write() should have thrown an exception because the encoder is closed.")
|
||||
} catch (e: IOException) {
|
||||
//Ok
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenSimpleFormIsUsed_thenItWorks() {
|
||||
StringWriter().use { it.write("something") }
|
||||
}
|
||||
}
|
||||
|
||||
class ThrowingExceptionListener : ExceptionListener {
|
||||
override fun exceptionThrown(e: Exception?) {
|
||||
if(e != null) {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
|
@ -55,7 +55,7 @@ public class InfluxDBConnectionLiveTest {
|
|||
|
||||
InfluxDB connection = connectDatabase();
|
||||
|
||||
// Create "baeldung and check for it
|
||||
// Create "baeldung" and check for it
|
||||
connection.createDatabase("baeldung");
|
||||
assertTrue(connection.databaseExists("baeldung"));
|
||||
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
<?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>
|
||||
<parent>
|
||||
<groupId>org.jenkins-ci.plugins</groupId>
|
||||
<artifactId>plugin</artifactId>
|
||||
<version>2.33</version>
|
||||
<relativePath />
|
||||
</parent>
|
||||
<artifactId>jenkins-hello-world</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>hpi</packaging>
|
||||
<properties>
|
||||
<!-- Baseline Jenkins version you use to build the plugin. Users must have this version or newer to run. -->
|
||||
<jenkins.version>2.7.3</jenkins.version>
|
||||
</properties>
|
||||
<name>Hello World Plugin</name>
|
||||
<description>A sample Jenkins Hello World plugin</description>
|
||||
<url>https://wiki.jenkins-ci.org/display/JENKINS/TODO+Plugin</url>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>MIT License</name>
|
||||
<url>http://opensource.org/licenses/MIT</url>
|
||||
</license>
|
||||
</licenses>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jenkins-ci.plugins</groupId>
|
||||
<artifactId>structs</artifactId>
|
||||
<version>1.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jenkins-ci.plugins.workflow</groupId>
|
||||
<artifactId>workflow-step-api</artifactId>
|
||||
<version>2.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jenkins-ci.plugins.workflow</groupId>
|
||||
<artifactId>workflow-cps</artifactId>
|
||||
<version>2.39</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jenkins-ci.plugins.workflow</groupId>
|
||||
<artifactId>workflow-job</artifactId>
|
||||
<version>2.11.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jenkins-ci.plugins.workflow</groupId>
|
||||
<artifactId>workflow-basic-steps</artifactId>
|
||||
<version>2.6</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jenkins-ci.plugins.workflow</groupId>
|
||||
<artifactId>workflow-durable-task-step</artifactId>
|
||||
<version>2.13</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jenkins-ci.plugins.workflow</groupId>
|
||||
<artifactId>workflow-api</artifactId>
|
||||
<version>2.20</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jenkins-ci.plugins.workflow</groupId>
|
||||
<artifactId>workflow-support</artifactId>
|
||||
<version>2.14</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>repo.jenkins-ci.org</id>
|
||||
<url>https://repo.jenkins-ci.org/public/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>repo.jenkins-ci.org</id>
|
||||
<url>https://repo.jenkins-ci.org/public/</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
</project>
|
|
@ -0,0 +1,20 @@
|
|||
package com.baeldung.jenkins.helloworld;
|
||||
|
||||
public class ProjectStats {
|
||||
|
||||
private final int classesNumber;
|
||||
private final int linesNumber;
|
||||
|
||||
public ProjectStats(int classesNumber, int linesNumber) {
|
||||
this.classesNumber = classesNumber;
|
||||
this.linesNumber = linesNumber;
|
||||
}
|
||||
|
||||
public int getClassesNumber() {
|
||||
return classesNumber;
|
||||
}
|
||||
|
||||
public int getLinesNumber() {
|
||||
return linesNumber;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
package com.baeldung.jenkins.helloworld;
|
||||
|
||||
import hudson.Extension;
|
||||
import hudson.FilePath;
|
||||
import hudson.Launcher;
|
||||
import hudson.model.AbstractBuild;
|
||||
import hudson.model.AbstractProject;
|
||||
import hudson.model.BuildListener;
|
||||
import hudson.tasks.BuildWrapper;
|
||||
import hudson.tasks.BuildWrapperDescriptor;
|
||||
import org.kohsuke.stapler.DataBoundConstructor;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Stack;
|
||||
|
||||
public class ProjectStatsBuildWrapper extends BuildWrapper {
|
||||
|
||||
private static final String REPORT_TEMPLATE_PATH = "/stats.html";
|
||||
private static final String PROJECT_NAME_VAR = "$PROJECT_NAME$";
|
||||
private static final String CLASSES_NUMBER_VAR = "$CLASSES_NUMBER$";
|
||||
private static final String LINES_NUMBER_VAR = "$LINES_NUMBER$";
|
||||
|
||||
@DataBoundConstructor
|
||||
public ProjectStatsBuildWrapper() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Environment setUp(AbstractBuild build, final Launcher launcher, BuildListener listener) {
|
||||
return new Environment() {
|
||||
@Override
|
||||
public boolean tearDown(AbstractBuild build, BuildListener listener)
|
||||
throws IOException, InterruptedException
|
||||
{
|
||||
ProjectStats stats = buildStats(build.getWorkspace());
|
||||
String report = generateReport(build.getProject().getDisplayName(), stats);
|
||||
File artifactsDir = build.getArtifactsDir();
|
||||
if (!artifactsDir.isDirectory()) {
|
||||
boolean success = artifactsDir.mkdirs();
|
||||
if (!success) {
|
||||
listener.getLogger().println("Can't create artifacts directory at "
|
||||
+ artifactsDir.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
String path = artifactsDir.getCanonicalPath() + REPORT_TEMPLATE_PATH;
|
||||
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path),
|
||||
StandardCharsets.UTF_8))) {
|
||||
writer.write(report);
|
||||
}
|
||||
return super.tearDown(build, listener);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static ProjectStats buildStats(FilePath root) throws IOException, InterruptedException {
|
||||
int classesNumber = 0;
|
||||
int linesNumber = 0;
|
||||
Stack<FilePath> toProcess = new Stack<>();
|
||||
toProcess.push(root);
|
||||
while (!toProcess.isEmpty()) {
|
||||
FilePath path = toProcess.pop();
|
||||
if (path.isDirectory()) {
|
||||
toProcess.addAll(path.list());
|
||||
} else if (path.getName().endsWith(".java")) {
|
||||
classesNumber++;
|
||||
linesNumber += countLines(path);
|
||||
}
|
||||
}
|
||||
return new ProjectStats(classesNumber, linesNumber);
|
||||
}
|
||||
|
||||
private static int countLines(FilePath path) throws IOException, InterruptedException {
|
||||
byte[] buffer = new byte[1024];
|
||||
int result = 1;
|
||||
try (InputStream in = path.read()) {
|
||||
while (true) {
|
||||
int read = in.read(buffer);
|
||||
if (read < 0) {
|
||||
return result;
|
||||
}
|
||||
for (int i = 0; i < read; i++) {
|
||||
if (buffer[i] == '\n') {
|
||||
result++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String generateReport(String projectName, ProjectStats stats) throws IOException {
|
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
||||
try (InputStream in = ProjectStatsBuildWrapper.class.getResourceAsStream(REPORT_TEMPLATE_PATH)) {
|
||||
byte[] buffer = new byte[1024];
|
||||
int read;
|
||||
while ((read = in.read(buffer)) >= 0) {
|
||||
bOut.write(buffer, 0, read);
|
||||
}
|
||||
}
|
||||
String content = new String(bOut.toByteArray(), StandardCharsets.UTF_8);
|
||||
content = content.replace(PROJECT_NAME_VAR, projectName);
|
||||
content = content.replace(CLASSES_NUMBER_VAR, String.valueOf(stats.getClassesNumber()));
|
||||
content = content.replace(LINES_NUMBER_VAR, String.valueOf(stats.getLinesNumber()));
|
||||
return content;
|
||||
}
|
||||
|
||||
@Extension
|
||||
public static final class DescriptorImpl extends BuildWrapperDescriptor {
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(AbstractProject<?, ?> item) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "Construct project stats during build";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>$PROJECT_NAME$</title>
|
||||
</head>
|
||||
<body>
|
||||
Project $PROJECT_NAME$:
|
||||
<table border="1">
|
||||
<tr>
|
||||
<th>Classes number</th>
|
||||
<th>Lines number</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>$CLASSES_NUMBER$</td>
|
||||
<td>$LINES_NUMBER$</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
|
@ -1,3 +1,5 @@
|
|||
### Relevant Articles:
|
||||
- [Intro to Jedis – the Java Redis Client Library](http://www.baeldung.com/jedis-java-redis-client-library)
|
||||
- [A Guide to Redis with Redisson](http://www.baeldung.com/redis-redisson)
|
||||
- [Intro to Lettuce – the Java Redis Client Library](http://www.baeldung.com/lettuce-java-redis-client-library)
|
||||
|
||||
|
|
|
@ -36,6 +36,13 @@
|
|||
<artifactId>redisson</artifactId>
|
||||
<version>3.3.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.lettuce</groupId>
|
||||
<artifactId>lettuce-core</artifactId>
|
||||
<version>5.0.1.RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
|
|
|
@ -0,0 +1,312 @@
|
|||
package com.baeldung;
|
||||
|
||||
import io.lettuce.core.LettuceFutures;
|
||||
import io.lettuce.core.RedisClient;
|
||||
import io.lettuce.core.RedisFuture;
|
||||
import io.lettuce.core.TransactionResult;
|
||||
import io.lettuce.core.api.StatefulRedisConnection;
|
||||
import io.lettuce.core.api.async.RedisAsyncCommands;
|
||||
import io.lettuce.core.api.sync.RedisCommands;
|
||||
import io.lettuce.core.pubsub.RedisPubSubListener;
|
||||
import io.lettuce.core.pubsub.StatefulRedisPubSubConnection;
|
||||
import io.lettuce.core.pubsub.api.async.RedisPubSubAsyncCommands;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class LettuceIntegrationLiveTest {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(LettuceIntegrationLiveTest.class);
|
||||
|
||||
private static StatefulRedisConnection<String, String> redisConnection;
|
||||
|
||||
private static RedisClient redisClient;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUp() {
|
||||
// Docker defaults to mapping redis port to 32768
|
||||
redisClient = RedisClient.create("redis://localhost:32768/");
|
||||
redisConnection = redisClient.connect();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void destroy() {
|
||||
redisConnection.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAString_thenSaveItAsRedisStringsSync() {
|
||||
|
||||
RedisCommands<String, String> syncCommands = redisConnection.sync();
|
||||
|
||||
String key = "key";
|
||||
String value = "value";
|
||||
|
||||
syncCommands.set(key, value);
|
||||
String response = syncCommands.get(key);
|
||||
|
||||
Assert.assertEquals(value, response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenValues_thenSaveAsRedisHashSync() {
|
||||
|
||||
RedisCommands<String, String> syncCommands = redisConnection.sync();
|
||||
|
||||
String recordName = "record1";
|
||||
String name = "FirstName";
|
||||
String value = "John";
|
||||
String surname = "LastName";
|
||||
String value1 = "Smith";
|
||||
|
||||
syncCommands.hset(recordName, name, value);
|
||||
syncCommands.hset(recordName, surname, value1);
|
||||
Map<String, String> record = syncCommands.hgetall(recordName);
|
||||
|
||||
Assert.assertEquals(record.get(name), value);
|
||||
Assert.assertEquals(record.get(surname), value1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAString_thenSaveItAsRedisStringsAsync() throws Exception {
|
||||
|
||||
RedisAsyncCommands<String, String> asyncCommands = redisConnection.async();
|
||||
|
||||
String key = "key";
|
||||
String value = "value";
|
||||
|
||||
asyncCommands.set(key, value);
|
||||
RedisFuture<String> redisFuture = asyncCommands.get(key);
|
||||
|
||||
String response = redisFuture.get();
|
||||
|
||||
Assert.assertEquals(value, response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenValues_thenSaveAsRedisHashAsync() throws Exception {
|
||||
|
||||
RedisAsyncCommands<String, String> asyncCommands = redisConnection.async();
|
||||
|
||||
String recordName = "record1";
|
||||
String name = "FirstName";
|
||||
String value = "John";
|
||||
String surname = "LastName";
|
||||
String value1 = "Smith";
|
||||
|
||||
asyncCommands.hset(recordName, name, value);
|
||||
asyncCommands.hset(recordName, surname, value1);
|
||||
RedisFuture<Map<String, String>> redisFuture = asyncCommands.hgetall(recordName);
|
||||
|
||||
Map<String, String> record = redisFuture.get();
|
||||
|
||||
Assert.assertEquals(record.get(name), value);
|
||||
Assert.assertEquals(record.get(surname), value1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenValues_thenSaveAsRedisListAsync() throws Exception {
|
||||
|
||||
RedisAsyncCommands<String, String> asyncCommands = redisConnection.async();
|
||||
|
||||
String listName = "tasks";
|
||||
String firstTask = "firstTask";
|
||||
String secondTask = "secondTask";
|
||||
|
||||
asyncCommands.del(listName);
|
||||
|
||||
asyncCommands.lpush(listName, firstTask);
|
||||
asyncCommands.lpush(listName, secondTask);
|
||||
RedisFuture<String> redisFuture = asyncCommands.rpop(listName);
|
||||
|
||||
String nextTask = redisFuture.get();
|
||||
|
||||
Assert.assertEquals(firstTask, nextTask);
|
||||
|
||||
asyncCommands.del(listName);
|
||||
|
||||
asyncCommands.lpush(listName, firstTask);
|
||||
asyncCommands.lpush(listName, secondTask);
|
||||
|
||||
redisFuture = asyncCommands.lpop(listName);
|
||||
|
||||
nextTask = redisFuture.get();
|
||||
|
||||
Assert.assertEquals(secondTask, nextTask);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenSetElements_thenSaveThemInRedisSetAsync() throws Exception {
|
||||
|
||||
RedisAsyncCommands<String, String> asyncCommands = redisConnection.async();
|
||||
|
||||
String countries = "countries";
|
||||
|
||||
String countryOne = "Spain";
|
||||
String countryTwo = "Ireland";
|
||||
String countryThree = "Ireland";
|
||||
|
||||
asyncCommands.sadd(countries, countryOne);
|
||||
|
||||
RedisFuture<Set<String>> countriesSetFuture = asyncCommands.smembers(countries);
|
||||
Assert.assertEquals(2, countriesSetFuture.get().size());
|
||||
|
||||
asyncCommands.sadd(countries, countryTwo);
|
||||
countriesSetFuture = asyncCommands.smembers(countries);
|
||||
Assert.assertEquals(2, countriesSetFuture.get().size());
|
||||
|
||||
asyncCommands.sadd(countries, countryThree);
|
||||
countriesSetFuture = asyncCommands.smembers(countries);
|
||||
Assert.assertEquals(2, countriesSetFuture.get().size());
|
||||
|
||||
RedisFuture<Boolean> exists = asyncCommands.sismember(countries, countryThree);
|
||||
assertTrue(exists.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenARanking_thenSaveItInRedisSortedSetAsync() throws Exception {
|
||||
|
||||
RedisAsyncCommands<String, String> asyncCommands = redisConnection.async();
|
||||
|
||||
String key = "sortedset";
|
||||
|
||||
asyncCommands.zadd(key, 1, "one");
|
||||
asyncCommands.zadd(key, 4, "zero");
|
||||
asyncCommands.zadd(key, 2, "two");
|
||||
|
||||
RedisFuture<List<String>> values = asyncCommands.zrevrange(key, 0, 3);
|
||||
Assert.assertEquals("zero", values.get().get(0));
|
||||
|
||||
values = asyncCommands.zrange(key, 0, 3);
|
||||
Assert.assertEquals("one", values.get().get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenMultipleOperationsThatNeedToBeExecutedAtomically_thenWrapThemInATransaction() throws Exception {
|
||||
|
||||
RedisAsyncCommands<String, String> asyncCommands = redisConnection.async();
|
||||
|
||||
// Start a transaction
|
||||
asyncCommands.multi();
|
||||
|
||||
// Add three sets to it, and save the future responses
|
||||
RedisFuture<String> result1 = asyncCommands.set("key1", "value1");
|
||||
RedisFuture<String> result2 = asyncCommands.set("key2", "value2");
|
||||
RedisFuture<String> result3 = asyncCommands.set("key3", "value3");
|
||||
|
||||
// Execute it
|
||||
RedisFuture<TransactionResult> execResult = asyncCommands.exec();
|
||||
|
||||
TransactionResult transactionResult = execResult.get();
|
||||
|
||||
// Get the three results in the transaction return
|
||||
String firstResult = transactionResult.get(0);
|
||||
String secondResult = transactionResult.get(0);
|
||||
String thirdResult = transactionResult.get(0);
|
||||
|
||||
// Our results are in both!
|
||||
assertTrue(firstResult.equals("OK"));
|
||||
assertTrue(secondResult.equals("OK"));
|
||||
assertTrue(thirdResult.equals("OK"));
|
||||
|
||||
assertTrue(result1.get().equals("OK"));
|
||||
assertTrue(result2.get().equals("OK"));
|
||||
assertTrue(result3.get().equals("OK"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenMultipleIndependentOperations_whenNetworkOptimizationIsImportant_thenFlushManually() throws Exception {
|
||||
|
||||
int iterations = 50;
|
||||
|
||||
RedisAsyncCommands<String, String> asyncCommands = redisConnection.async();
|
||||
|
||||
asyncCommands.setAutoFlushCommands(false);
|
||||
|
||||
List<RedisFuture<?>> futures = new ArrayList<>();
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
futures.add(asyncCommands.set("key" + i, "value" + i));
|
||||
}
|
||||
|
||||
asyncCommands.flushCommands();
|
||||
|
||||
// Wait until all futures complete
|
||||
boolean result = LettuceFutures.awaitAll(5, TimeUnit.SECONDS, futures.toArray(new RedisFuture[futures.size()]));
|
||||
|
||||
asyncCommands.setAutoFlushCommands(true);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenPubSubChannel_whenMessage_thenMessageReceived() throws Exception {
|
||||
|
||||
Listener listener = new Listener();
|
||||
StatefulRedisPubSubConnection<String, String> connection = redisClient.connectPubSub();
|
||||
StatefulRedisPubSubConnection<String, String> pubconnection = redisClient.connectPubSub();
|
||||
connection.addListener(listener);
|
||||
|
||||
RedisPubSubAsyncCommands<String, String> async = connection.async();
|
||||
async.subscribe("channel");
|
||||
|
||||
RedisPubSubAsyncCommands<String, String> pubasync = pubconnection.async();
|
||||
RedisFuture<Long> result = pubasync.publish("channel", "hithere");
|
||||
|
||||
// Need a long wait for publish to complete, depending on system.
|
||||
result.get(15, TimeUnit.SECONDS);
|
||||
assertTrue(listener.getMessage().equals("hithere"));
|
||||
|
||||
}
|
||||
|
||||
private static class Listener implements RedisPubSubListener<String, String> {
|
||||
|
||||
private String message;
|
||||
|
||||
String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void message(String channel, String message) {
|
||||
log.debug("Got {} on {}", message, channel);
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void message(String pattern, String channel, String message) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subscribed(String channel, long count) {
|
||||
log.debug("Subscribed to {}", channel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void psubscribed(String pattern, long count) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsubscribed(String channel, long count) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void punsubscribed(String pattern, long count) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -43,6 +43,10 @@
|
|||
<groupId>javax.json.bind</groupId>
|
||||
<artifactId>javax.json.bind-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Dependencies for Yasson -->
|
||||
<!-- <dependency> -->
|
||||
|
@ -198,4 +202,5 @@
|
|||
<geronimo-json_1.1_spec.version>1.0</geronimo-json_1.1_spec.version>
|
||||
</properties>
|
||||
|
||||
|
||||
</project>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package com.baeldung.actuator;
|
||||
package com.baeldung.reactive.actuator;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
|
|
@ -1,4 +1,4 @@
|
|||
package com.baeldung.actuator;
|
||||
package com.baeldung.reactive.actuator;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.annotation.*;
|
||||
import org.springframework.stereotype.Component;
|
|
@ -1,4 +1,4 @@
|
|||
package com.baeldung.actuator;
|
||||
package com.baeldung.reactive.actuator;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
|
|
@ -1 +1,4 @@
|
|||
logging.level.root=INFO
|
||||
logging.level.root=INFO
|
||||
|
||||
management.endpoints.web.expose=*
|
||||
info.app.name=Spring Boot 2 actuator Application
|
|
@ -1,6 +1,5 @@
|
|||
package com.baeldung.actuator;
|
||||
package com.baeldung.reactive.actuator;
|
||||
|
||||
import com.baeldung.jsonb.Spring5Application;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
@ -10,12 +9,14 @@ import org.springframework.http.HttpStatus;
|
|||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import com.baeldung.reactive.Spring5ReactiveApplication;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Spring5Application.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Spring5ReactiveApplication.class)
|
||||
public class ActuatorInfoIntegrationTest {
|
||||
|
||||
@Autowired
|
|
@ -0,0 +1,3 @@
|
|||
## Relevant articles:
|
||||
|
||||
- [Spring Security 5 -OAuth2 Login](http://www.baeldung.com/spring-security-5-oauth2-login)
|
|
@ -43,10 +43,6 @@
|
|||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-hateoas</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectreactor</groupId>
|
||||
<artifactId>reactor-spring</artifactId>
|
||||
|
|
|
@ -17,7 +17,6 @@ public class SecurityConfig {
|
|||
public SecurityWebFilterChain securitygWebFilterChain(ServerHttpSecurity http) {
|
||||
return http.authorizeExchange()
|
||||
.pathMatchers("/admin").hasAuthority("ROLE_ADMIN")
|
||||
.pathMatchers("/actuator/**").permitAll()
|
||||
.anyExchange().authenticated()
|
||||
.and().formLogin()
|
||||
.and().build();
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
server.port=8081
|
||||
management.endpoints.web.expose=*
|
||||
info.app.name=Spring Boot 2 actuator Application
|
||||
|
||||
logging.level.root=INFO
|
|
@ -1,6 +1,8 @@
|
|||
### Spring Boot Security Auto-Configuration
|
||||
|
||||
- mvn clean install
|
||||
- uncomment in application.properties spring.profiles.active=basic # for basic auth config
|
||||
- uncomment in application.properties spring.profiles.active=form # for form based auth config
|
||||
- uncomment actuator dependency simultaneously with the line from main class
|
||||
- uncomment actuator dependency simultaneously with the line from basic auth main class
|
||||
- uncomment security properties for easy testing. If not random will be generated.
|
||||
|
||||
### CURL commands
|
||||
- curl -X POST -u baeldung-admin:baeldung -d grant_type=client_credentials -d username=baeldung-admin -d password=baeldung http://localhost:8080/oauth/token
|
||||
|
|
|
@ -43,6 +43,10 @@
|
|||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security.oauth</groupId>
|
||||
<artifactId>spring-security-oauth2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package com.baeldung.springbootsecurity;
|
||||
package com.baeldung.springbootsecurity.basic_auth;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
@ -7,7 +7,7 @@ import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration
|
|||
@SpringBootApplication(exclude = {
|
||||
SecurityAutoConfiguration.class
|
||||
// ,ManagementWebSecurityAutoConfiguration.class
|
||||
})
|
||||
}, scanBasePackages = "com.baeldung.springbootsecurity.basic_auth")
|
||||
public class SpringBootSecurityApplication {
|
||||
|
||||
public static void main(String[] args) {
|
|
@ -1,7 +1,6 @@
|
|||
package com.baeldung.springbootsecurity.config;
|
||||
package com.baeldung.springbootsecurity.basic_auth.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
|
@ -9,8 +8,7 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
|
|||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@Profile("basic")
|
||||
public class BasicConfiguration extends WebSecurityConfigurerAdapter {
|
||||
public class BasicAuthConfiguration extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
|
@ -1,39 +0,0 @@
|
|||
package com.baeldung.springbootsecurity.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
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;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@Profile("form")
|
||||
public class FormLoginConfiguration extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user")
|
||||
.password("password")
|
||||
.roles("USER")
|
||||
.and()
|
||||
.withUser("admin")
|
||||
.password("password")
|
||||
.roles("USER", "ADMIN");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest()
|
||||
.authenticated()
|
||||
.and()
|
||||
.formLogin()
|
||||
.and()
|
||||
.httpBasic();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package com.baeldung.springbootsecurity.oauth2resource;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@EnableResourceServer
|
||||
@SpringBootApplication(scanBasePackages = "com.baeldung.springbootsecurity.oauth2resource")
|
||||
public class SpringBootOAuth2ResourceApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
new SpringApplicationBuilder()
|
||||
.profiles("resource")
|
||||
.sources(SpringBootOAuth2ResourceApplication.class)
|
||||
.build()
|
||||
.run(args);
|
||||
}
|
||||
|
||||
@RestController
|
||||
class SecuredResourceController {
|
||||
|
||||
@GetMapping("/securedResource")
|
||||
public String securedResource() {
|
||||
return "Baeldung Secured Resource OK";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package com.baeldung.springbootsecurity.oauth2server;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
@EnableResourceServer
|
||||
@EnableAuthorizationServer
|
||||
@SpringBootApplication(scanBasePackages = "com.baeldung.springbootsecurity.oauth2server")
|
||||
public class SpringBootAuthorizationServerApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringBootAuthorizationServerApplication.class, args);
|
||||
}
|
||||
|
||||
@RestController
|
||||
class UserController {
|
||||
|
||||
@GetMapping("/user")
|
||||
public Principal user(Principal user) {
|
||||
return user;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package com.baeldung.springbootsecurity.oauth2server.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
|
||||
|
||||
@Configuration
|
||||
@Profile("authz")
|
||||
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
|
||||
|
||||
@Autowired
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
@Override
|
||||
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
|
||||
endpoints.authenticationManager(authenticationManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
|
||||
clients
|
||||
.inMemory()
|
||||
.withClient("baeldung")
|
||||
.secret("baeldung")
|
||||
.authorizedGrantTypes("client_credentials", "password", "authorization_code")
|
||||
.scopes("openid", "read")
|
||||
.autoApprove(true)
|
||||
.and()
|
||||
.withClient("baeldung-admin")
|
||||
.secret("baeldung")
|
||||
.authorizedGrantTypes("authorization_code", "client_credentials", "refresh_token")
|
||||
.scopes("read", "write")
|
||||
.autoApprove(true);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.baeldung.springbootsecurity.oauth2sso;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
|
||||
@EnableOAuth2Sso
|
||||
@SpringBootApplication(scanBasePackages = "com.baeldung.springbootsecurity.oauth2sso")
|
||||
public class SpringBootOAuth2SsoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
new SpringApplicationBuilder()
|
||||
.profiles("sso")
|
||||
.sources(SpringBootOAuth2SsoApplication.class)
|
||||
.build()
|
||||
.run(args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
security.user.password=password
|
||||
security.oauth2.client.client-id=client
|
||||
security.oauth2.client.client-secret=secret
|
|
@ -0,0 +1,2 @@
|
|||
server.port=8081
|
||||
security.oauth2.resource.userInfoUri=http://localhost:8080/user
|
|
@ -0,0 +1,9 @@
|
|||
server.port=8082
|
||||
security.oauth2.client.clientId=<generated_app_id>
|
||||
security.oauth2.client.clientSecret=<app_secret>
|
||||
security.oauth2.client.accessTokenUri=https://graph.facebook.com/oauth/access_token
|
||||
security.oauth2.client.userAuthorizationUri=https://www.facebook.com/dialog/oauth
|
||||
security.oauth2.client.tokenName=oauth_token
|
||||
security.oauth2.client.authenticationScheme=query
|
||||
security.oauth2.client.clientAuthenticationScheme=form
|
||||
security.oauth2.resource.userInfoUri=https://graph.facebook.com/me
|
|
@ -1,4 +1,4 @@
|
|||
#spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration
|
||||
#spring.profiles.active=form
|
||||
#spring.profiles.active=basic
|
||||
#security.user.password=password
|
||||
#security.user.password=password
|
||||
#security.oauth2.client.client-id=client
|
||||
#security.oauth2.client.client-secret=secret
|
||||
|
|
|
@ -1,106 +0,0 @@
|
|||
package com.baeldung.springbootsecurity;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.embedded.LocalServerPort;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = RANDOM_PORT)
|
||||
@ActiveProfiles("form")
|
||||
public class FormConfigurationIntegrationTest {
|
||||
|
||||
@Autowired TestRestTemplate restTemplate;
|
||||
@LocalServerPort int port;
|
||||
|
||||
@Test
|
||||
public void whenLoginPageIsRequested_ThenSuccess() {
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
httpHeaders.setAccept(Collections.singletonList(MediaType.TEXT_HTML));
|
||||
ResponseEntity<String> responseEntity = restTemplate.exchange("/login", HttpMethod.GET, new HttpEntity<Void>(httpHeaders), String.class);
|
||||
assertEquals(HttpStatus.OK, responseEntity.getStatusCode());
|
||||
assertTrue(responseEntity
|
||||
.getBody()
|
||||
.contains("_csrf"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenTryingToLoginWithCorrectCredentials_ThenAuthenticateWithSuccess() {
|
||||
HttpHeaders httpHeaders = getHeaders();
|
||||
httpHeaders.setAccept(Collections.singletonList(MediaType.TEXT_HTML));
|
||||
httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
MultiValueMap<String, String> form = getFormSubmitCorrectCredentials();
|
||||
ResponseEntity<String> responseEntity = this.restTemplate.exchange("/login", HttpMethod.POST, new HttpEntity<>(form, httpHeaders), String.class);
|
||||
assertEquals(responseEntity.getStatusCode(), HttpStatus.FOUND);
|
||||
assertTrue(responseEntity
|
||||
.getHeaders()
|
||||
.getLocation()
|
||||
.toString()
|
||||
.endsWith(this.port + "/"));
|
||||
assertNotNull(responseEntity
|
||||
.getHeaders()
|
||||
.get("Set-Cookie"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenTryingToLoginWithInorrectCredentials_ThenAuthenticationFailed() {
|
||||
HttpHeaders httpHeaders = getHeaders();
|
||||
httpHeaders.setAccept(Collections.singletonList(MediaType.TEXT_HTML));
|
||||
httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
MultiValueMap<String, String> form = getFormSubmitIncorrectCredentials();
|
||||
ResponseEntity<String> responseEntity = this.restTemplate.exchange("/login", HttpMethod.POST, new HttpEntity<>(form, httpHeaders), String.class);
|
||||
assertEquals(responseEntity.getStatusCode(), HttpStatus.FOUND);
|
||||
assertTrue(responseEntity
|
||||
.getHeaders()
|
||||
.getLocation()
|
||||
.toString()
|
||||
.endsWith(this.port + "/login?error"));
|
||||
assertNull(responseEntity
|
||||
.getHeaders()
|
||||
.get("Set-Cookie"));
|
||||
}
|
||||
|
||||
private MultiValueMap<String, String> getFormSubmitCorrectCredentials() {
|
||||
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
|
||||
form.set("username", "user");
|
||||
form.set("password", "password");
|
||||
return form;
|
||||
}
|
||||
|
||||
private MultiValueMap<String, String> getFormSubmitIncorrectCredentials() {
|
||||
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
|
||||
form.set("username", "user");
|
||||
form.set("password", "wrongpassword");
|
||||
return form;
|
||||
}
|
||||
|
||||
private HttpHeaders getHeaders() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
ResponseEntity<String> page = this.restTemplate.getForEntity("/login", String.class);
|
||||
assertEquals(page.getStatusCode(), HttpStatus.OK);
|
||||
String cookie = page
|
||||
.getHeaders()
|
||||
.getFirst("Set-Cookie");
|
||||
headers.set("Cookie", cookie);
|
||||
Pattern pattern = Pattern.compile("(?s).*name=\"_csrf\".*?value=\"([^\"]+).*");
|
||||
Matcher matcher = pattern.matcher(page.getBody());
|
||||
assertTrue(matcher.matches());
|
||||
headers.set("X-CSRF-TOKEN", matcher.group(1));
|
||||
return headers;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package com.baeldung.springbootsecurity;
|
||||
package com.baeldung.springbootsecurity.basic_auth;
|
||||
|
||||
import com.baeldung.springbootsecurity.basic_auth.SpringBootSecurityApplication;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
@ -8,7 +9,6 @@ import org.springframework.boot.test.context.SpringBootTest;
|
|||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -20,9 +20,8 @@ import static org.junit.Assert.assertTrue;
|
|||
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = RANDOM_PORT)
|
||||
@ActiveProfiles("basic")
|
||||
public class BasicConfigurationIntegrationTest {
|
||||
@SpringBootTest(webEnvironment = RANDOM_PORT, classes = SpringBootSecurityApplication.class)
|
||||
public class BasicAuthConfigurationIntegrationTest {
|
||||
|
||||
TestRestTemplate restTemplate;
|
||||
URL base;
|
|
@ -0,0 +1,75 @@
|
|||
package com.baeldung.springbootsecurity.oauth2server;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
|
||||
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
|
||||
import org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException;
|
||||
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
|
||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = RANDOM_PORT, classes = SpringBootAuthorizationServerApplication.class)
|
||||
@ActiveProfiles("authz")
|
||||
public class CustomConfigAuthorizationServerIntegrationTest {
|
||||
|
||||
@Value("${local.server.port}") protected int port;
|
||||
|
||||
@Test
|
||||
public void whenAccessTokenIsRequested_ThenAccessTokenValueIsNotNull() {
|
||||
ClientCredentialsResourceDetails resourceDetails = getClientCredentialsResourceDetails();
|
||||
resourceDetails.setClientId("baeldung");
|
||||
resourceDetails.setClientSecret("baeldung");
|
||||
resourceDetails.setScope(singletonList("read"));
|
||||
DefaultOAuth2ClientContext clientContext = new DefaultOAuth2ClientContext();
|
||||
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails, clientContext);
|
||||
restTemplate.setMessageConverters(singletonList(new MappingJackson2HttpMessageConverter()));
|
||||
OAuth2AccessToken accessToken = restTemplate.getAccessToken();
|
||||
assertNotNull(accessToken);
|
||||
|
||||
}
|
||||
|
||||
@Test(expected = OAuth2AccessDeniedException.class)
|
||||
public void whenAccessTokenIsRequestedWithInvalidException_ThenExceptionIsThrown() {
|
||||
ClientCredentialsResourceDetails resourceDetails = getClientCredentialsResourceDetails();
|
||||
resourceDetails.setClientId("baeldung");
|
||||
resourceDetails.setClientSecret("baeldung");
|
||||
resourceDetails.setScope(singletonList("write"));
|
||||
DefaultOAuth2ClientContext clientContext = new DefaultOAuth2ClientContext();
|
||||
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails, clientContext);
|
||||
restTemplate.setMessageConverters(singletonList(new MappingJackson2HttpMessageConverter()));
|
||||
restTemplate.getAccessToken();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenAccessTokenIsRequestedByClientWithWriteScope_ThenAccessTokenIsNotNull() {
|
||||
ClientCredentialsResourceDetails resourceDetails = getClientCredentialsResourceDetails();
|
||||
resourceDetails.setClientId("baeldung-admin");
|
||||
resourceDetails.setClientSecret("baeldung");
|
||||
resourceDetails.setScope(singletonList("write"));
|
||||
DefaultOAuth2ClientContext clientContext = new DefaultOAuth2ClientContext();
|
||||
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails, clientContext);
|
||||
restTemplate.setMessageConverters(singletonList(new MappingJackson2HttpMessageConverter()));
|
||||
OAuth2AccessToken accessToken = restTemplate.getAccessToken();
|
||||
assertNotNull(accessToken);
|
||||
}
|
||||
|
||||
private ClientCredentialsResourceDetails getClientCredentialsResourceDetails() {
|
||||
ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
|
||||
resourceDetails.setAccessTokenUri(format("http://localhost:%d/oauth/token", port));
|
||||
resourceDetails.setGrantType("client_credentials");
|
||||
return resourceDetails;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package com.baeldung.springbootsecurity.oauth2server;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
|
||||
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
|
||||
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
|
||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = RANDOM_PORT, classes = SpringBootAuthorizationServerApplication.class,
|
||||
properties = { "security.oauth2.client.client-id=client", "security.oauth2.client.client-secret=secret" })
|
||||
public class DefaultConfigAuthorizationServerIntegrationTest {
|
||||
|
||||
@Value("${local.server.port}") protected int port;
|
||||
|
||||
@Test
|
||||
public void whenAccessTokenIsRequested_ThenAccessTokenValueIsNotNull() {
|
||||
ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
|
||||
resourceDetails.setAccessTokenUri(format("http://localhost:%d/oauth/token", port));
|
||||
resourceDetails.setClientId("client");
|
||||
resourceDetails.setClientSecret("secret");
|
||||
resourceDetails.setGrantType("client_credentials");
|
||||
resourceDetails.setScope(asList("read", "write"));
|
||||
DefaultOAuth2ClientContext clientContext = new DefaultOAuth2ClientContext();
|
||||
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails, clientContext);
|
||||
restTemplate.setMessageConverters(singletonList(new MappingJackson2HttpMessageConverter()));
|
||||
OAuth2AccessToken accessToken = restTemplate.getAccessToken();
|
||||
assertNotNull(accessToken);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -45,6 +45,24 @@
|
|||
<version>${spring-data-elasticsearch.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.spatial4j</groupId>
|
||||
<artifactId>spatial4j</artifactId>
|
||||
<version>0.4.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.vividsolutions</groupId>
|
||||
<artifactId>jts</artifactId>
|
||||
<version>1.13</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>xerces</groupId>
|
||||
<artifactId>xercesImpl</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
|
|
|
@ -0,0 +1,179 @@
|
|||
package com.baeldung.elasticsearch;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
|
||||
import org.elasticsearch.action.index.IndexResponse;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.common.geo.ShapeRelation;
|
||||
import org.elasticsearch.common.geo.builders.ShapeBuilder;
|
||||
import org.elasticsearch.common.unit.DistanceUnit;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.baeldung.spring.data.es.config.Config;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = Config.class)
|
||||
public class GeoQueriesTest {
|
||||
|
||||
public static final String WONDERS_OF_WORLD = "wonders-of-world";
|
||||
public static final String WONDERS = "Wonders";
|
||||
@Autowired
|
||||
private ElasticsearchTemplate elasticsearchTemplate;
|
||||
|
||||
@Autowired
|
||||
private Client client;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
String jsonObject = "{\"Wonders\":{\"properties\":{\"name\":{\"type\":\"string\",\"index\":\"not_analyzed\"},\"region\":{\"type\":\"geo_shape\",\"tree\":\"quadtree\",\"precision\":\"1m\"},\"location\":{\"type\":\"geo_point\"}}}}";
|
||||
CreateIndexRequest req = new CreateIndexRequest(WONDERS_OF_WORLD);
|
||||
req.mapping(WONDERS, jsonObject);
|
||||
client.admin()
|
||||
.indices()
|
||||
.create(req)
|
||||
.actionGet();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenGeoShapeData_whenExecutedGeoShapeQuery_thenResultNonEmpty() {
|
||||
String jsonObject = "{\"name\":\"Agra\",\"region\":{\"type\":\"envelope\",\"coordinates\":[[75,25],[80.1,30.2]]}}";
|
||||
IndexResponse response = client.prepareIndex(WONDERS_OF_WORLD, WONDERS)
|
||||
.setSource(jsonObject)
|
||||
.get();
|
||||
String tajMahalId = response.getId();
|
||||
client.admin()
|
||||
.indices()
|
||||
.prepareRefresh(WONDERS_OF_WORLD)
|
||||
.get();
|
||||
|
||||
QueryBuilder qb = QueryBuilders.geoShapeQuery("region", ShapeBuilder.newEnvelope()
|
||||
.topLeft(74.00, 24.0)
|
||||
.bottomRight(81.1, 31.2))
|
||||
.relation(ShapeRelation.WITHIN);
|
||||
|
||||
SearchResponse searchResponse = client.prepareSearch(WONDERS_OF_WORLD)
|
||||
.setTypes(WONDERS)
|
||||
.setQuery(qb)
|
||||
.execute()
|
||||
.actionGet();
|
||||
List<String> ids = Arrays.stream(searchResponse.getHits()
|
||||
.getHits())
|
||||
.map(hit -> {
|
||||
return hit.getId();
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
assertTrue(ids.contains(tajMahalId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenGeoPointData_whenExecutedGeoBoundingBoxQuery_thenResultNonEmpty() {
|
||||
String jsonObject = "{\"name\":\"Pyramids of Giza\",\"location\":[31.131302,29.976480]}";
|
||||
IndexResponse response = client.prepareIndex(WONDERS_OF_WORLD, WONDERS)
|
||||
.setSource(jsonObject)
|
||||
.get();
|
||||
String pyramidsOfGizaId = response.getId();
|
||||
client.admin()
|
||||
.indices()
|
||||
.prepareRefresh(WONDERS_OF_WORLD)
|
||||
.get();
|
||||
|
||||
QueryBuilder qb = QueryBuilders.geoBoundingBoxQuery("location")
|
||||
.bottomLeft(28, 30)
|
||||
.topRight(31, 32);
|
||||
|
||||
SearchResponse searchResponse = client.prepareSearch(WONDERS_OF_WORLD)
|
||||
.setTypes(WONDERS)
|
||||
.setQuery(qb)
|
||||
.execute()
|
||||
.actionGet();
|
||||
List<String> ids = Arrays.stream(searchResponse.getHits()
|
||||
.getHits())
|
||||
.map(hit -> {
|
||||
return hit.getId();
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
assertTrue(ids.contains(pyramidsOfGizaId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenGeoPointData_whenExecutedGeoDistanceQuery_thenResultNonEmpty() {
|
||||
String jsonObject = "{\"name\":\"Lighthouse of alexandria\",\"location\":[31.131302,29.976480]}";
|
||||
IndexResponse response = client.prepareIndex(WONDERS_OF_WORLD, WONDERS)
|
||||
.setSource(jsonObject)
|
||||
.get();
|
||||
String lighthouseOfAlexandriaId = response.getId();
|
||||
client.admin()
|
||||
.indices()
|
||||
.prepareRefresh(WONDERS_OF_WORLD)
|
||||
.get();
|
||||
|
||||
QueryBuilder qb = QueryBuilders.geoDistanceQuery("location")
|
||||
.point(29.976, 31.131)
|
||||
.distance(10, DistanceUnit.MILES);
|
||||
|
||||
SearchResponse searchResponse = client.prepareSearch(WONDERS_OF_WORLD)
|
||||
.setTypes(WONDERS)
|
||||
.setQuery(qb)
|
||||
.execute()
|
||||
.actionGet();
|
||||
List<String> ids = Arrays.stream(searchResponse.getHits()
|
||||
.getHits())
|
||||
.map(hit -> {
|
||||
return hit.getId();
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
assertTrue(ids.contains(lighthouseOfAlexandriaId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenGeoPointData_whenExecutedGeoPolygonQuery_thenResultNonEmpty() {
|
||||
String jsonObject = "{\"name\":\"The Great Rann of Kutch\",\"location\":[69.859741,23.733732]}";
|
||||
IndexResponse response = client.prepareIndex(WONDERS_OF_WORLD, WONDERS)
|
||||
.setSource(jsonObject)
|
||||
.get();
|
||||
String greatRannOfKutchid = response.getId();
|
||||
client.admin()
|
||||
.indices()
|
||||
.prepareRefresh(WONDERS_OF_WORLD)
|
||||
.get();
|
||||
|
||||
QueryBuilder qb = QueryBuilders.geoPolygonQuery("location")
|
||||
.addPoint(22.733, 68.859)
|
||||
.addPoint(24.733, 68.859)
|
||||
.addPoint(23, 70.859);
|
||||
|
||||
SearchResponse searchResponse = client.prepareSearch(WONDERS_OF_WORLD)
|
||||
.setTypes(WONDERS)
|
||||
.setQuery(qb)
|
||||
.execute()
|
||||
.actionGet();
|
||||
List<String> ids = Arrays.stream(searchResponse.getHits()
|
||||
.getHits())
|
||||
.map(hit -> {
|
||||
return hit.getId();
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
assertTrue(ids.contains(greatRannOfKutchid));
|
||||
}
|
||||
|
||||
@After
|
||||
public void destroy() {
|
||||
elasticsearchTemplate.deleteIndex(WONDERS_OF_WORLD);
|
||||
}
|
||||
|
||||
}
|
|
@ -110,7 +110,7 @@
|
|||
|
||||
<properties>
|
||||
<!-- Spring -->
|
||||
<org.springframework.version>4.3.4.RELEASE</org.springframework.version>
|
||||
<org.springframework.version>5.0.2.RELEASE</org.springframework.version>
|
||||
<org.springframework.security.version>4.2.0.RELEASE</org.springframework.security.version>
|
||||
|
||||
<!-- persistence -->
|
||||
|
@ -142,4 +142,4 @@
|
|||
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
|
|
|
@ -8,24 +8,14 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
public class ExampleOne extends HttpServlet {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
response.setContentType("text/html");
|
||||
PrintWriter out = response.getWriter();
|
||||
out.println(
|
||||
"<!DOCTYPE html><html>" +
|
||||
"<head>" +
|
||||
"<meta charset=\"UTF-8\" />" +
|
||||
"<title>HTML Rendered by Servlet</title>" +
|
||||
"</head>" +
|
||||
"<body>" +
|
||||
"<h1>HTML Rendered by Servlet</h1></br>" +
|
||||
"<p>This page was rendered by the ExampleOne Servlet!</p>" +
|
||||
"</body>" +
|
||||
"</html>"
|
||||
);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
response.setContentType("text/html");
|
||||
PrintWriter out = response.getWriter();
|
||||
out.println("<!DOCTYPE html><html>" + "<head>" + "<meta charset=\"UTF-8\" />" + "<title>HTML Rendered by Servlet</title>" + "</head>" + "<body>" + "<h1>HTML Rendered by Servlet</h1></br>" + "<p>This page was rendered by the ExampleOne Servlet!</p>"
|
||||
+ "</body>" + "</html>");
|
||||
}
|
||||
}
|
|
@ -7,18 +7,14 @@ import javax.servlet.http.HttpServlet;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@WebServlet(
|
||||
name = "ExampleThree",
|
||||
description = "JSP Servlet With Annotations",
|
||||
urlPatterns = {"/ExampleThree"}
|
||||
)
|
||||
@WebServlet(name = "ExampleThree", description = "JSP Servlet With Annotations", urlPatterns = { "/ExampleThree" })
|
||||
public class ExampleThree extends HttpServlet {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
String message = request.getParameter("message");
|
||||
request.setAttribute("text", message);
|
||||
request.getRequestDispatcher("/jsp/ExampleThree.jsp").forward(request, response);
|
||||
}
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
String message = request.getParameter("message");
|
||||
request.setAttribute("text", message);
|
||||
request.getRequestDispatcher("/jsp/ExampleThree.jsp").forward(request, response);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import org.springframework.web.servlet.ModelAndView;
|
|||
|
||||
@Controller
|
||||
public class ErrorController {
|
||||
|
||||
|
||||
@RequestMapping(value = "500Error", method = RequestMethod.GET)
|
||||
public void throwRuntimeException() {
|
||||
throw new NullPointerException("Throwing a null pointer exception");
|
||||
|
@ -34,19 +34,18 @@ public class ErrorController {
|
|||
errorMsg = "Http Error Code : 404. Resource not found";
|
||||
break;
|
||||
}
|
||||
// Handle other 4xx error codes.
|
||||
// Handle other 4xx error codes.
|
||||
case 500: {
|
||||
errorMsg = "Http Error Code : 500. Internal Server Error";
|
||||
break;
|
||||
}
|
||||
// Handle other 5xx error codes.
|
||||
// Handle other 5xx error codes.
|
||||
}
|
||||
errorPage.addObject("errorMsg", errorMsg);
|
||||
return errorPage;
|
||||
}
|
||||
|
||||
private int getErrorCode(HttpServletRequest httpRequest) {
|
||||
return (Integer) httpRequest
|
||||
.getAttribute("javax.servlet.error.status_code");
|
||||
return (Integer) httpRequest.getAttribute("javax.servlet.error.status_code");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,15 +14,15 @@ import com.baeldung.spring.service.RawDBDemoGeoIPLocationService;
|
|||
@Controller
|
||||
public class GeoIPTestController {
|
||||
private RawDBDemoGeoIPLocationService locationService;
|
||||
|
||||
public GeoIPTestController() throws IOException {
|
||||
locationService
|
||||
= new RawDBDemoGeoIPLocationService();
|
||||
locationService = new RawDBDemoGeoIPLocationService();
|
||||
}
|
||||
@RequestMapping(value="/GeoIPTest", method = RequestMethod.POST)
|
||||
|
||||
@RequestMapping(value = "/GeoIPTest", method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public GeoIP getLocation(
|
||||
@RequestParam(value="ipAddress", required=true) String ipAddress) throws Exception {
|
||||
|
||||
public GeoIP getLocation(@RequestParam(value = "ipAddress", required = true) String ipAddress) throws Exception {
|
||||
|
||||
return locationService.getLocation(ipAddress);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import org.springframework.web.context.support.ServletContextResource;
|
|||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
|
|
|
@ -5,15 +5,15 @@ public class GeoIP {
|
|||
private String city;
|
||||
private String latitude;
|
||||
private String longitude;
|
||||
|
||||
|
||||
public GeoIP() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public GeoIP(String ipAddress) {
|
||||
this.ipAddress = ipAddress;
|
||||
}
|
||||
|
||||
|
||||
public GeoIP(String ipAddress, String city, String latitude, String longitude) {
|
||||
this.ipAddress = ipAddress;
|
||||
this.city = city;
|
||||
|
@ -52,5 +52,5 @@ public class GeoIP {
|
|||
public void setLongitude(String longitude) {
|
||||
this.longitude = longitude;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -9,18 +9,18 @@ import com.maxmind.geoip2.DatabaseReader;
|
|||
import com.maxmind.geoip2.exception.GeoIp2Exception;
|
||||
import com.maxmind.geoip2.model.CityResponse;
|
||||
|
||||
public class RawDBDemoGeoIPLocationService{
|
||||
public class RawDBDemoGeoIPLocationService {
|
||||
private DatabaseReader dbReader;
|
||||
|
||||
|
||||
public RawDBDemoGeoIPLocationService() throws IOException {
|
||||
File database = new File("your-path-to-db-file");
|
||||
dbReader = new DatabaseReader.Builder(database).build();
|
||||
}
|
||||
|
||||
|
||||
public GeoIP getLocation(String ip) throws IOException, GeoIp2Exception {
|
||||
InetAddress ipAddress = InetAddress.getByName(ip);
|
||||
CityResponse response = dbReader.city(ipAddress);
|
||||
|
||||
|
||||
String cityName = response.getCity().getName();
|
||||
String latitude = response.getLocation().getLatitude().toString();
|
||||
String longitude = response.getLocation().getLongitude().toString();
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
|
||||
xsi:schemaLocation="
|
||||
http://java.sun.com/xml/ns/javaee
|
||||
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"
|
||||
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
|
||||
version="3.1"
|
||||
>
|
||||
|
||||
<display-name>Spring MVC XML Application</display-name>
|
||||
|
||||
<!-- Spring root -->
|
||||
|
@ -65,4 +64,4 @@
|
|||
<error-page>
|
||||
<location>/errors</location>
|
||||
</error-page>
|
||||
</web-app>
|
||||
</web-app>
|
||||
|
|
|
@ -10,22 +10,21 @@ import com.maxmind.geoip2.DatabaseReader;
|
|||
import com.maxmind.geoip2.exception.GeoIp2Exception;
|
||||
import com.maxmind.geoip2.model.CityResponse;
|
||||
|
||||
|
||||
public class GeoIpIntegrationTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void givenIP_whenFetchingCity_thenReturnsCityData() throws IOException, GeoIp2Exception {
|
||||
File database = new File("your-path-to-db-file");
|
||||
DatabaseReader dbReader = new DatabaseReader.Builder(database).build();
|
||||
|
||||
|
||||
InetAddress ipAddress = InetAddress.getByName("your-public-ip");
|
||||
CityResponse response = dbReader.city(ipAddress);
|
||||
|
||||
|
||||
String countryName = response.getCountry().getName();
|
||||
String cityName = response.getCity().getName();
|
||||
String postal = response.getPostal().getCode();
|
||||
String state = response.getLeastSpecificSubdivision().getName();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>spring-reactive-websocket</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>spring-reactive-websocket</name>
|
||||
<description>Reactive WebSockets with Spring 5</description>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-integration</artifactId>
|
||||
<version>2.0.0.M7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
<version>2.0.0.M7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<scope>compile</scope>
|
||||
<version>RELEASE</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
|
||||
</project>
|
|
@ -0,0 +1,11 @@
|
|||
package com.baeldung;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class Event {
|
||||
private String eventId;
|
||||
private String eventDt;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package com.baeldung;
|
||||
|
||||
import java.net.URI;
|
||||
import java.time.Duration;
|
||||
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.web.reactive.socket.WebSocketMessage;
|
||||
import org.springframework.web.reactive.socket.client.ReactorNettyWebSocketClient;
|
||||
import org.springframework.web.reactive.socket.client.WebSocketClient;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@SpringBootApplication
|
||||
public class ReactiveWebSocketApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ReactiveWebSocketApplication.class, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Spring Reactive WebSocket Client
|
||||
* **/
|
||||
@Bean
|
||||
CommandLineRunner runner() {
|
||||
return run -> {
|
||||
WebSocketClient client = new ReactorNettyWebSocketClient();
|
||||
client.execute(URI.create("ws://localhost:8080/event-emitter"), session -> session.send(Mono.just(session.textMessage("event-me-from-spring-reactive-client")))
|
||||
.thenMany(session.receive()
|
||||
.map(WebSocketMessage::getPayloadAsText)
|
||||
.log())
|
||||
.then())
|
||||
.block();
|
||||
// .block(Duration.ofSeconds(10L));//force timeout after given duration
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package com.baeldung;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.reactive.HandlerMapping;
|
||||
import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping;
|
||||
import org.springframework.web.reactive.socket.WebSocketHandler;
|
||||
import org.springframework.web.reactive.socket.server.support.WebSocketHandlerAdapter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Configuration
|
||||
public class ReactiveWebSocketConfiguration {
|
||||
|
||||
@Autowired
|
||||
private WebSocketHandler webSocketHandler;
|
||||
|
||||
@Bean
|
||||
public HandlerMapping webSocketHandlerMapping() {
|
||||
Map<String, WebSocketHandler> map = new HashMap<>();
|
||||
map.put("/event-emitter", webSocketHandler);
|
||||
|
||||
SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping();
|
||||
handlerMapping.setOrder(1);
|
||||
handlerMapping.setUrlMap(map);
|
||||
return handlerMapping;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public WebSocketHandlerAdapter handlerAdapter() {
|
||||
return new WebSocketHandlerAdapter();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package com.baeldung;
|
||||
|
||||
import org.springframework.web.reactive.socket.WebSocketSession;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.reactive.socket.WebSocketHandler;
|
||||
import org.springframework.web.reactive.socket.WebSocketMessage;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
@Component
|
||||
public class ReactiveWebSocketHandler implements WebSocketHandler {
|
||||
|
||||
private Flux<Event> eventFlux;
|
||||
private Flux<Event> intervalFlux;
|
||||
|
||||
/**
|
||||
* Here we prepare a Flux that will emit a message every second
|
||||
*/
|
||||
@PostConstruct
|
||||
private void init() throws InterruptedException {
|
||||
|
||||
eventFlux = Flux.generate(e -> {
|
||||
Event event = new Event(UUID.randomUUID()
|
||||
.toString(),
|
||||
LocalDateTime.now()
|
||||
.toString());
|
||||
e.next(event);
|
||||
});
|
||||
|
||||
intervalFlux = Flux.interval(Duration.ofMillis(1000L))
|
||||
.zipWith(eventFlux, (time, event) -> event);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* On each new client session, send the message flux to the client.
|
||||
* Spring subscribes to the flux and send every new flux event to the WebSocketSession object
|
||||
* @param session
|
||||
* @return Mono<Void>
|
||||
*/
|
||||
@Override
|
||||
public Mono<Void> handle(WebSocketSession webSocketSession) {
|
||||
ObjectMapper json = new ObjectMapper();
|
||||
return webSocketSession.send(intervalFlux.map(event -> {
|
||||
try {
|
||||
String jsonEvent = json.writeValueAsString(event);
|
||||
System.out.println(jsonEvent);
|
||||
return jsonEvent;
|
||||
} catch (JsonProcessingException e) {
|
||||
e.printStackTrace();
|
||||
return "";
|
||||
}
|
||||
})
|
||||
.map(webSocketSession::textMessage))
|
||||
|
||||
.and(webSocketSession.receive()
|
||||
.map(WebSocketMessage::getPayloadAsText)
|
||||
.log());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Baeldung: Spring 5 Reactive Client WebSocket (Browser)</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="events"></div>
|
||||
<script>
|
||||
var clientWebSocket = new WebSocket("ws://localhost:8080/event-emitter");
|
||||
clientWebSocket.onopen = function() {
|
||||
console.log("clientWebSocket.onopen", clientWebSocket);
|
||||
console.log("clientWebSocket.readyState", "websocketstatus");
|
||||
clientWebSocket.send("event-me-from-browser");
|
||||
}
|
||||
clientWebSocket.onclose = function(error) {
|
||||
console.log("clientWebSocket.onclose", clientWebSocket, error);
|
||||
events("Closing connection");
|
||||
}
|
||||
clientWebSocket.onerror = function(error) {
|
||||
console.log("clientWebSocket.onerror", clientWebSocket, error);
|
||||
events("An error occured");
|
||||
}
|
||||
clientWebSocket.onmessage = function(error) {
|
||||
console.log("clientWebSocket.onmessage", clientWebSocket, error);
|
||||
events(error.data);
|
||||
}
|
||||
function events(responseEvent) {
|
||||
document.querySelector(".events").innerHTML += responseEvent + "<br>";
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,14 @@
|
|||
package org.baeldung.methodsecurity.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@PreAuthorize("hasRole('VIEWER')")
|
||||
public @interface IsViewer {
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
package org.baeldung.testmethodsecurity.config;
|
||||
package org.baeldung.methodsecurity.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
|
||||
|
||||
@Configuration
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
|
||||
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung.testmethodsecurity.entity;
|
||||
package org.baeldung.methodsecurity.entity;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
|
@ -6,15 +6,15 @@ import org.springframework.security.core.GrantedAuthority;
|
|||
import org.springframework.security.core.userdetails.User;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class CustomUser extends User{
|
||||
|
||||
public class CustomUser extends User {
|
||||
|
||||
private String nickName;
|
||||
|
||||
public CustomUser(String username, String password, Collection<? extends GrantedAuthority> authorities) {
|
||||
super(username, password, authorities);
|
||||
}
|
||||
|
||||
public CustomUser(String username, String password, Collection<? extends GrantedAuthority> authorities,String nickName) {
|
||||
|
||||
public CustomUser(String username, String password, Collection<? extends GrantedAuthority> authorities, String nickName) {
|
||||
super(username, password, authorities);
|
||||
this.nickName = nickName;
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package org.baeldung.methodsecurity.repository;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.baeldung.methodsecurity.entity.CustomUser;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class UserRoleRepository {
|
||||
|
||||
static Map<String, CustomUser> DB_BASED_USER_MAPPING;
|
||||
|
||||
static {
|
||||
DB_BASED_USER_MAPPING = new LinkedHashMap<>();
|
||||
DB_BASED_USER_MAPPING.put("jane", new CustomUser("jane", "1234", getGrantedAuthorities("ROLE_USER", "ROLE_VIEWER"), "jane"));
|
||||
DB_BASED_USER_MAPPING.put("john", new CustomUser("john", "1234", getGrantedAuthorities("ROLE_EDITOR", "ROLE_ADMIN"), "jane"));
|
||||
DB_BASED_USER_MAPPING.put("jack", new CustomUser("jack", "1234", getGrantedAuthorities("ROLE_USER", "ROLE_REVIEWER"), "jane"));
|
||||
}
|
||||
|
||||
private static List<GrantedAuthority> getGrantedAuthorities(String... roles) {
|
||||
ArrayList<GrantedAuthority> authorities = new ArrayList<>();
|
||||
for (String role : roles) {
|
||||
authorities.add(new SimpleGrantedAuthority(role));
|
||||
}
|
||||
return authorities;
|
||||
}
|
||||
|
||||
public CustomUser loadUserByUserName(String username) {
|
||||
if (DB_BASED_USER_MAPPING.containsKey(username)) {
|
||||
return DB_BASED_USER_MAPPING.get(username);
|
||||
}
|
||||
throw new UsernameNotFoundException("User " + username + " cannot be found");
|
||||
}
|
||||
|
||||
public boolean isValidUsername(String username) {
|
||||
return DB_BASED_USER_MAPPING.containsKey(username);
|
||||
}
|
||||
|
||||
public boolean isValidRole(String roleName) {
|
||||
return roleName.startsWith("ROLE_");
|
||||
}
|
||||
|
||||
public List<String> getAllUsernames() {
|
||||
List<String> usernames = new ArrayList<>();
|
||||
usernames.add("jane");
|
||||
usernames.add("john");
|
||||
usernames.add("jack");
|
||||
return usernames;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package org.baeldung.testmethodsecurity.service;
|
||||
package org.baeldung.methodsecurity.service;
|
||||
|
||||
import org.baeldung.testmethodsecurity.repository.UserRoleRepository;
|
||||
import org.baeldung.methodsecurity.repository.UserRoleRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
|
@ -0,0 +1,18 @@
|
|||
package org.baeldung.methodsecurity.service;
|
||||
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
public class SystemService {
|
||||
|
||||
public String getSystemYear(){
|
||||
return "2017";
|
||||
}
|
||||
|
||||
public String getSystemDate(){
|
||||
return "31-12-2017";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
package org.baeldung.methodsecurity.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.security.RolesAllowed;
|
||||
|
||||
import org.baeldung.methodsecurity.annotation.IsViewer;
|
||||
import org.baeldung.methodsecurity.entity.CustomUser;
|
||||
import org.baeldung.methodsecurity.repository.UserRoleRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.annotation.Secured;
|
||||
import org.springframework.security.access.prepost.PostAuthorize;
|
||||
import org.springframework.security.access.prepost.PostFilter;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.access.prepost.PreFilter;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class UserRoleService {
|
||||
|
||||
@Autowired
|
||||
UserRoleRepository userRoleRepository;
|
||||
|
||||
@Secured("ROLE_VIEWER")
|
||||
public String getUsername() {
|
||||
SecurityContext securityContext = SecurityContextHolder.getContext();
|
||||
return securityContext.getAuthentication().getName();
|
||||
}
|
||||
|
||||
@Secured({ "ROLE_VIEWER", "ROLE_EDITOR" })
|
||||
public boolean isValidUsername(String username) {
|
||||
return userRoleRepository.isValidUsername(username);
|
||||
}
|
||||
|
||||
@RolesAllowed("ROLE_VIEWER")
|
||||
public String getUsername2() {
|
||||
SecurityContext securityContext = SecurityContextHolder.getContext();
|
||||
return securityContext.getAuthentication().getName();
|
||||
}
|
||||
|
||||
@RolesAllowed({ "ROLE_VIEWER", "ROLE_EDITOR" })
|
||||
public boolean isValidUsername2(String username) {
|
||||
return userRoleRepository.isValidUsername(username);
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_VIEWER')")
|
||||
public String getUsernameInUpperCase() {
|
||||
return getUsername().toUpperCase();
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('SYS_ADMIN')")
|
||||
public String getUsernameLC() {
|
||||
return getUsername().toLowerCase();
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_VIEWER') or hasRole('ROLE_EDITOR')")
|
||||
public boolean isValidUsername3(String username) {
|
||||
return userRoleRepository.isValidUsername(username);
|
||||
}
|
||||
|
||||
@PreAuthorize("#username == authentication.principal.username")
|
||||
public String getMyRoles(String username) {
|
||||
SecurityContext securityContext = SecurityContextHolder.getContext();
|
||||
return securityContext.getAuthentication().getAuthorities().stream().map(auth -> auth.getAuthority()).collect(Collectors.joining(","));
|
||||
}
|
||||
|
||||
@PostAuthorize("#username == authentication.principal.username")
|
||||
public String getMyRoles2(String username) {
|
||||
SecurityContext securityContext = SecurityContextHolder.getContext();
|
||||
return securityContext.getAuthentication().getAuthorities().stream().map(auth -> auth.getAuthority()).collect(Collectors.joining(","));
|
||||
}
|
||||
|
||||
@PostAuthorize("returnObject.username == authentication.principal.nickName")
|
||||
public CustomUser loadUserDetail(String username) {
|
||||
return userRoleRepository.loadUserByUserName(username);
|
||||
}
|
||||
|
||||
@PreFilter("filterObject != authentication.principal.username")
|
||||
public String joinUsernames(List<String> usernames) {
|
||||
return usernames.stream().collect(Collectors.joining(";"));
|
||||
}
|
||||
|
||||
@PreFilter(value = "filterObject != authentication.principal.username", filterTarget = "usernames")
|
||||
public String joinUsernamesAndRoles(List<String> usernames, List<String> roles) {
|
||||
return usernames.stream().collect(Collectors.joining(";")) + ":" + roles.stream().collect(Collectors.joining(";"));
|
||||
}
|
||||
|
||||
@PostFilter("filterObject != authentication.principal.username")
|
||||
public List<String> getAllUsernamesExceptCurrent() {
|
||||
return userRoleRepository.getAllUsernames();
|
||||
}
|
||||
|
||||
@IsViewer
|
||||
public String getUsername4() {
|
||||
SecurityContext securityContext = SecurityContextHolder.getContext();
|
||||
return securityContext.getAuthentication().getName();
|
||||
}
|
||||
|
||||
@PreAuthorize("#username == authentication.principal.username")
|
||||
@PostAuthorize("returnObject.username == authentication.principal.nickName")
|
||||
public CustomUser securedLoadUserDetail(String username) {
|
||||
return userRoleRepository.loadUserByUserName(username);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
package org.baeldung.testmethodsecurity.repository;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.baeldung.testmethodsecurity.entity.CustomUser;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class UserRoleRepository {
|
||||
|
||||
static Map<String,CustomUser> DB_BASED_USER_MAPPING;
|
||||
|
||||
static{
|
||||
DB_BASED_USER_MAPPING = new LinkedHashMap<>();
|
||||
DB_BASED_USER_MAPPING.put("jane", new CustomUser("jane","1234", getGrantedAuthorities("ROLE_USER","ROLE_VIEWER"),"jane"));
|
||||
DB_BASED_USER_MAPPING.put("john", new CustomUser("john","1234", getGrantedAuthorities("ROLE_EDITOR","ROLE_ADMIN"),"jane"));
|
||||
DB_BASED_USER_MAPPING.put("jack", new CustomUser("jack","1234", getGrantedAuthorities("ROLE_USER","ROLE_REVIEWER"),"jane"));
|
||||
}
|
||||
|
||||
private static List<GrantedAuthority> getGrantedAuthorities(String...roles){
|
||||
ArrayList<GrantedAuthority> authorities = new ArrayList<>();
|
||||
for (String role : roles){
|
||||
authorities.add(new SimpleGrantedAuthority(role));
|
||||
}
|
||||
return authorities;
|
||||
}
|
||||
|
||||
public CustomUser loadUserByUserName(String username){
|
||||
if (DB_BASED_USER_MAPPING.containsKey(username)){
|
||||
return DB_BASED_USER_MAPPING.get(username);
|
||||
}
|
||||
throw new UsernameNotFoundException("User "+username+" cannot be found");
|
||||
}
|
||||
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
package org.baeldung.testmethodsecurity.service;
|
||||
|
||||
import org.baeldung.testmethodsecurity.entity.CustomUser;
|
||||
import org.baeldung.testmethodsecurity.repository.UserRoleRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PostAuthorize;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class UserRoleService {
|
||||
|
||||
@Autowired
|
||||
UserRoleRepository userRoleRepository;
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_VIEWER') or hasAuthority('SYS_ADMIN')")
|
||||
public String getUsername(){
|
||||
SecurityContext securityContext = SecurityContextHolder.getContext();
|
||||
return securityContext.getAuthentication().getName();
|
||||
}
|
||||
|
||||
@PostAuthorize("returnObject.username == authentication.principal.nickName")
|
||||
public CustomUser loadUserDetail(String username){
|
||||
return userRoleRepository.loadUserByUserName(username);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package org.baeldung.methodsecurity;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.baeldung.methodsecurity.service.SystemService;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.test.context.support.WithMockUser;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
public class TestClassLevelSecurity {
|
||||
|
||||
@Autowired
|
||||
SystemService systemService;
|
||||
|
||||
@Configuration
|
||||
@ComponentScan("org.baeldung.methodsecurity.*")
|
||||
public static class SpringConfig {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(username="john",roles={"ADMIN"})
|
||||
public void givenRoleAdmin_whenCallGetSystemYear_return2017(){
|
||||
String systemYear = systemService.getSystemYear();
|
||||
assertEquals("2017",systemYear);
|
||||
}
|
||||
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
@WithMockUser(username="john",roles={"VIEWER"})
|
||||
public void givenRoleViewer_whenCallGetSystemYear_returnAccessDenied(){
|
||||
String systemYear = systemService.getSystemYear();
|
||||
assertEquals("2017",systemYear);
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(username="john",roles={"ADMIN"})
|
||||
public void givenRoleAdmin_whenCallGetSystemDate_returnDate(){
|
||||
String systemYear = systemService.getSystemDate();
|
||||
assertEquals("31-12-2017",systemYear);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,176 @@
|
|||
package org.baeldung.methodsecurity;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.baeldung.methodsecurity.service.UserRoleService;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
|
||||
import org.springframework.security.test.context.support.WithAnonymousUser;
|
||||
import org.springframework.security.test.context.support.WithMockUser;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
public class TestMethodSecurity {
|
||||
|
||||
@Autowired
|
||||
UserRoleService userRoleService;
|
||||
|
||||
@Configuration
|
||||
@ComponentScan("org.baeldung.methodsecurity.*")
|
||||
public static class SpringConfig {
|
||||
|
||||
}
|
||||
|
||||
@Test(expected = AuthenticationCredentialsNotFoundException.class)
|
||||
public void givenNoSecurity_whenCallGetUsername_thenReturnException() {
|
||||
String userName = userRoleService.getUsername();
|
||||
assertEquals("john", userName);
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(username = "john", roles = { "VIEWER" })
|
||||
public void givenRoleViewer_whenCallGetUsername_thenReturnUsername() {
|
||||
String userName = userRoleService.getUsername();
|
||||
assertEquals("john", userName);
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(username = "john", roles = { "EDITOR" })
|
||||
public void givenUsernameJohn_whenCallIsValidUsername_thenReturnTrue() {
|
||||
boolean isValid = userRoleService.isValidUsername("john");
|
||||
assertEquals(true, isValid);
|
||||
}
|
||||
|
||||
@Test(expected = AccessDeniedException.class)
|
||||
@WithMockUser(username = "john", roles = { "ADMIN" })
|
||||
public void givenRoleAdmin_whenCallGetUsername_thenReturnAccessDenied() {
|
||||
userRoleService.getUsername();
|
||||
}
|
||||
|
||||
@Test(expected = AccessDeniedException.class)
|
||||
@WithMockUser(username = "john", roles = { "USER" })
|
||||
public void givenRoleUser_whenCallGetUsername2_thenReturnAccessDenied() {
|
||||
userRoleService.getUsername2();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(username = "john", roles = { "VIEWER", "EDITOR" })
|
||||
public void givenRoleViewer_whenCallGetUsername2_thenReturnUsername() {
|
||||
String userName = userRoleService.getUsername2();
|
||||
assertEquals("john", userName);
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(username = "john", roles = { "VIEWER" })
|
||||
public void givenUsernameJerry_whenCallIsValidUsername2_thenReturnFalse() {
|
||||
boolean isValid = userRoleService.isValidUsername2("jerry");
|
||||
assertEquals(false, isValid);
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(username = "JOHN", authorities = { "SYS_ADMIN" })
|
||||
public void givenAuthoritySysAdmin_whenCallGetUsernameInLowerCase_thenReturnUsername() {
|
||||
String username = userRoleService.getUsernameLC();
|
||||
assertEquals("john", username);
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(username = "john", roles = { "ADMIN", "USER", "VIEWER" })
|
||||
public void givenUserJohn_whenCallGetMyRolesWithJohn_thenReturnRoles() {
|
||||
String roles = userRoleService.getMyRoles("john");
|
||||
assertEquals("ROLE_ADMIN,ROLE_USER,ROLE_VIEWER", roles);
|
||||
}
|
||||
|
||||
@Test(expected = AccessDeniedException.class)
|
||||
@WithMockUser(username = "john", roles = { "ADMIN", "USER", "VIEWER" })
|
||||
public void givenUserJane_whenCallGetMyRolesWithJane_thenAccessDenied() {
|
||||
userRoleService.getMyRoles("jane");
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(username = "john", roles = { "ADMIN", "USER", "VIEWER" })
|
||||
public void givenUserJohn_whenCallGetMyRoles2WithJohn_thenReturnRoles() {
|
||||
String roles = userRoleService.getMyRoles2("john");
|
||||
assertEquals("ROLE_ADMIN,ROLE_USER,ROLE_VIEWER", roles);
|
||||
}
|
||||
|
||||
@Test(expected = AccessDeniedException.class)
|
||||
@WithMockUser(username = "john", roles = { "ADMIN", "USER", "VIEWER" })
|
||||
public void givenUserJane_whenCallGetMyRoles2WithJane_thenAccessDenied() {
|
||||
userRoleService.getMyRoles2("jane");
|
||||
}
|
||||
|
||||
@Test(expected = AccessDeniedException.class)
|
||||
@WithAnonymousUser
|
||||
public void givenAnomynousUser_whenCallGetUsername_thenAccessDenied() {
|
||||
userRoleService.getUsername();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockJohnViewer
|
||||
public void givenMockedJohnViewer_whenCallGetUsername_thenReturnUsername() {
|
||||
String userName = userRoleService.getUsername();
|
||||
assertEquals("john", userName);
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(username = "jane")
|
||||
public void givenListContainCurrentUsername_whenJoinUsernames_thenReturnUsernames() {
|
||||
List<String> usernames = new ArrayList<>();
|
||||
usernames.add("jane");
|
||||
usernames.add("john");
|
||||
usernames.add("jack");
|
||||
String containCurrentUser = userRoleService.joinUsernames(usernames);
|
||||
assertEquals("john;jack", containCurrentUser);
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(username = "john")
|
||||
public void givenListContainCurrentUsername_whenCallJoinUsernamesAndRoles_thenReturnUsernameAndRoles() {
|
||||
List<String> usernames = new ArrayList<>();
|
||||
usernames.add("jane");
|
||||
usernames.add("john");
|
||||
usernames.add("jack");
|
||||
|
||||
List<String> roles = new ArrayList<>();
|
||||
roles.add("ROLE_ADMIN");
|
||||
roles.add("ROLE_TEST");
|
||||
|
||||
String containCurrentUser = userRoleService.joinUsernamesAndRoles(usernames, roles);
|
||||
assertEquals("jane;jack:ROLE_ADMIN;ROLE_TEST", containCurrentUser);
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(username = "john")
|
||||
public void givenUserJohn_whenCallGetAllUsernamesExceptCurrent_thenReturnOtherusernames() {
|
||||
List<String> others = userRoleService.getAllUsernamesExceptCurrent();
|
||||
assertEquals(2, others.size());
|
||||
assertTrue(others.contains("jane"));
|
||||
assertTrue(others.contains("jack"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(username = "john", roles = { "VIEWER" })
|
||||
public void givenRoleViewer_whenCallGetUsername4_thenReturnUsername() {
|
||||
String userName = userRoleService.getUsername4();
|
||||
assertEquals("john", userName);
|
||||
}
|
||||
|
||||
@Test(expected = AccessDeniedException.class)
|
||||
@WithMockUser(username = "john")
|
||||
public void givenDefaultRole_whenCallGetUsername4_thenAccessDenied() {
|
||||
userRoleService.getUsername4();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
package org.baeldung.testmethodsecurity;
|
||||
package org.baeldung.methodsecurity;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.baeldung.testmethodsecurity.service.UserRoleService;
|
||||
import org.baeldung.methodsecurity.service.UserRoleService;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
@ -14,20 +14,20 @@ import org.springframework.test.context.junit4.SpringRunner;
|
|||
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
@WithMockUser(username="john",roles={"VIEWER"})
|
||||
@WithMockUser(username = "john", roles = { "VIEWER" })
|
||||
public class TestWithMockUserAtClassLevel {
|
||||
|
||||
|
||||
@Test
|
||||
public void givenRoleViewer_whenCallGetUsername_thenReturnUsername(){
|
||||
public void givenRoleViewer_whenCallGetUsername_thenReturnUsername() {
|
||||
String currentUserName = userService.getUsername();
|
||||
assertEquals("john",currentUserName);
|
||||
assertEquals("john", currentUserName);
|
||||
}
|
||||
|
||||
|
||||
@Autowired
|
||||
UserRoleService userService;
|
||||
|
||||
|
||||
@Configuration
|
||||
@ComponentScan("org.baeldung.testmethodsecurity.*")
|
||||
@ComponentScan("org.baeldung.methodsecurity.*")
|
||||
public static class SpringConfig {
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package org.baeldung.methodsecurity;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.baeldung.methodsecurity.entity.CustomUser;
|
||||
import org.baeldung.methodsecurity.service.UserRoleService;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.test.context.support.WithUserDetails;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
public class TestWithUserDetails {
|
||||
|
||||
@Autowired
|
||||
UserRoleService userService;
|
||||
|
||||
@Configuration
|
||||
@ComponentScan("org.baeldung.methodsecurity.*")
|
||||
public static class SpringConfig {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUserDetails(value = "john", userDetailsServiceBeanName = "userDetailService")
|
||||
public void whenJohn_callLoadUserDetail_thenOK() {
|
||||
CustomUser user = userService.loadUserDetail("jane");
|
||||
assertEquals("jane", user.getNickName());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUserDetails(value = "jane", userDetailsServiceBeanName = "userDetailService")
|
||||
public void givenJane_callSecuredLoadUserDetailWithJane_thenOK() {
|
||||
CustomUser user = userService.securedLoadUserDetail("jane");
|
||||
assertEquals("jane", user.getNickName());
|
||||
assertEquals("jane", user.getUsername());
|
||||
}
|
||||
|
||||
@Test(expected = AccessDeniedException.class)
|
||||
@WithUserDetails(value = "john", userDetailsServiceBeanName = "userDetailService")
|
||||
public void givenJohn_callSecuredLoadUserDetailWithJane_thenAccessDenied() {
|
||||
userService.securedLoadUserDetail("jane");
|
||||
}
|
||||
|
||||
@Test(expected = AccessDeniedException.class)
|
||||
@WithUserDetails(value = "john", userDetailsServiceBeanName = "userDetailService")
|
||||
public void givenJohn_callSecuredLoadUserDetailWithJohn_thenAccessDenied() {
|
||||
userService.securedLoadUserDetail("john");
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung.testmethodsecurity;
|
||||
package org.baeldung.methodsecurity;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
|
@ -1,57 +0,0 @@
|
|||
package org.baeldung.testmethodsecurity;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.baeldung.testmethodsecurity.service.UserRoleService;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.test.context.support.WithAnonymousUser;
|
||||
import org.springframework.security.test.context.support.WithMockUser;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
public class TestMethodSecurity{
|
||||
|
||||
@Autowired
|
||||
UserRoleService userRoleService;
|
||||
|
||||
@Configuration
|
||||
@ComponentScan("org.baeldung.testmethodsecurity.*")
|
||||
public static class SpringConfig {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(username="john",roles={"VIEWER"})
|
||||
public void givenRoleViewer_whenCallGetUsername_thenReturnUsername(){
|
||||
String userName = userRoleService.getUsername();
|
||||
assertEquals("john", userName);
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(username="john",authorities={"SYS_ADMIN"})
|
||||
public void givenAuthoritySysAdmin_whenCallGetUsername_thenReturnUsername(){
|
||||
String userName = userRoleService.getUsername();
|
||||
assertEquals("john", userName);
|
||||
}
|
||||
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
@WithAnonymousUser
|
||||
public void givenAnomynousUser_whenCallGetUsername_thenAccessDenied(){
|
||||
userRoleService.getUsername();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockJohnViewer
|
||||
public void givenMockedJohnViewer_whenCallGetUsername_thenReturnUsername(){
|
||||
String userName = userRoleService.getUsername();
|
||||
assertEquals("john", userName);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
package org.baeldung.testmethodsecurity;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.baeldung.testmethodsecurity.entity.CustomUser;
|
||||
import org.baeldung.testmethodsecurity.service.UserRoleService;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.test.context.support.WithUserDetails;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
public class TestWithUserDetails {
|
||||
|
||||
@Autowired
|
||||
UserRoleService userService;
|
||||
|
||||
@Configuration
|
||||
@ComponentScan("org.baeldung.testmethodsecurity.*")
|
||||
public static class SpringConfig {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithUserDetails(value="john",userDetailsServiceBeanName="userDetailService")
|
||||
public void whenJohn_callLoadUserDetail_thenOK(){
|
||||
CustomUser user = userService.loadUserDetail("jane");
|
||||
assertEquals("jane",user.getNickName());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package org.baeldung.web.controller;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
@Controller
|
||||
@RequestMapping(value = "/custom")
|
||||
public class LoginController {
|
||||
|
||||
@Autowired
|
||||
private AuthenticationManager authManager;
|
||||
|
||||
public LoginController() {
|
||||
super();
|
||||
}
|
||||
|
||||
// API
|
||||
|
||||
// custom login
|
||||
|
||||
@RequestMapping(value = "/login", method = RequestMethod.POST)
|
||||
public void login(@RequestParam("username") final String username, @RequestParam("password") final String password, final HttpServletRequest request) {
|
||||
UsernamePasswordAuthenticationToken authReq =
|
||||
new UsernamePasswordAuthenticationToken(username, password);
|
||||
Authentication auth = authManager.authenticate(authReq);
|
||||
SecurityContext sc = SecurityContextHolder.getContext();
|
||||
sc.setAuthentication(auth);
|
||||
HttpSession session = request.getSession(true);
|
||||
session.setAttribute("SPRING_SECURITY_CONTEXT", sc);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package org.baeldung.web.controller;
|
||||
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
@Controller
|
||||
@RequestMapping(value = "/custom")
|
||||
public class PrintUserController {
|
||||
|
||||
public PrintUserController() {
|
||||
super();
|
||||
}
|
||||
|
||||
// API
|
||||
|
||||
// print user
|
||||
|
||||
@RequestMapping(value = "/print", method = RequestMethod.GET)
|
||||
public void printUser() {
|
||||
SecurityContext sc = SecurityContextHolder.getContext();
|
||||
System.out.println("Logged User: "+sc.getAuthentication().getName());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package org.baeldung.security.spring;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.BeanIds;
|
||||
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.builders.WebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
public class ManualSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
public ManualSecurityConfig() {
|
||||
super();
|
||||
}
|
||||
|
||||
// java config
|
||||
|
||||
@Override
|
||||
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.inMemoryAuthentication().withUser("user1").password("user1Pass").authorities("ROLE_USER").and().withUser("admin").password("adminPass").authorities("ROLE_ADMIN");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(final WebSecurity web) throws Exception {
|
||||
web.ignoring().antMatchers("/resources/**");
|
||||
}
|
||||
|
||||
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean() throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(final HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeRequests()
|
||||
.mvcMatchers("/custom/login").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.httpBasic()
|
||||
.and()
|
||||
.headers().cacheControl().disable()
|
||||
.and()
|
||||
.csrf().disable()
|
||||
;
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package org.baeldung.security.spring;
|
||||
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.baeldung.spring.MvcConfig;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.mock.web.MockHttpSession;
|
||||
import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@WebAppConfiguration
|
||||
@ContextConfiguration(classes = { MvcConfig.class, ManualSecurityConfig.class })
|
||||
public class ManualSecurityIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
WebApplicationContext wac;
|
||||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mockMvc = MockMvcBuilders.webAppContextSetup(wac).apply(SecurityMockMvcConfigurers.springSecurity()).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute custom login and access the endpoint
|
||||
*/
|
||||
@Test
|
||||
public void whenLoginIsSuccessFulThenEndpointCanBeAccessedAndCurrentUserPrinted() throws Exception {
|
||||
|
||||
mockMvc.perform(get("/custom/print"))
|
||||
.andExpect(status().isUnauthorized());
|
||||
|
||||
HttpSession session = mockMvc.perform(post("/custom/login").param("username", "user1").param("password", "user1Pass"))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn()
|
||||
.getRequest()
|
||||
.getSession();
|
||||
|
||||
mockMvc.perform(get("/custom/print").session((MockHttpSession) session))
|
||||
.andExpect(status().is2xxSuccessful());
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue