Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
407607131f
|
@ -1,3 +1,4 @@
|
|||
### Relevant Articles:
|
||||
- [Microsoft Word Processing in Java with Apache POI](http://www.baeldung.com/java-microsoft-word-with-apache-poi)
|
||||
- [Working with Microsoft Excel in Java](http://www.baeldung.com/java-microsoft-excel)
|
||||
- [Creating a MS PowerPoint Presentation in Java](https://github.com/eugenp/tutorials/tree/master/apache-poi)
|
||||
|
|
|
@ -37,3 +37,6 @@
|
|||
- [Iterable to Stream in Java](http://www.baeldung.com/java-iterable-to-stream)
|
||||
- [Converting String to Stream of chars](http://www.baeldung.com/java-string-to-stream)
|
||||
- [How to Iterate Over a Stream With Indices](http://www.baeldung.com/java-stream-indices)
|
||||
- [Efficient Word Frequency Calculator in Java](http://www.baeldung.com/java-word-frequency)
|
||||
- [Primitive Type Streams in Java 8](http://www.baeldung.com/java-8-primitive-streams)
|
||||
- [Fail-Safe Iterator vs Fail-Fast Iterator](http://www.baeldung.com/java-fail-safe-vs-fail-fast-iterator)
|
||||
|
|
|
@ -33,3 +33,4 @@
|
|||
- [Daemon Threads in Java](http://www.baeldung.com/java-daemon-thread)
|
||||
- [Implementing a Runnable vs Extending a Thread](http://www.baeldung.com/java-runnable-vs-extending-thread)
|
||||
- [How to Kill a Java Thread](http://www.baeldung.com/java-thread-stop)
|
||||
- [How to Wait for Threads to Finish in the ExecutorService](http://www.baeldung.com/java-executor-wait-for-threads)
|
||||
|
|
|
@ -118,3 +118,11 @@
|
|||
- [Implementing a Binary Tree in Java](http://www.baeldung.com/java-binary-tree)
|
||||
- [A Guide to ThreadLocalRandom in Java](http://www.baeldung.com/java-thread-local-random)
|
||||
- [RegEx for matching Date Pattern in Java](http://www.baeldung.com/java-date-regular-expressions)
|
||||
- [Introduction to the JDBC RowSet Interface in Java](http://www.baeldung.com/java-jdbc-rowset)
|
||||
- [Nested Classes in Java](http://www.baeldung.com/java-nested-classes)
|
||||
- [A Guide to Java Loops](http://www.baeldung.com/java-loops)
|
||||
- [Varargs in Java](http://www.baeldung.com/java-varargs)
|
||||
- [A Guide to HashSet in Java](http://www.baeldung.com/java-hashset)
|
||||
- [A Guide to Inner Interfaces in Java](http://www.baeldung.com/java-inner-interfaces)
|
||||
- [Polymorphism in Java](http://www.baeldung.com/java-polymorphism)
|
||||
- [Recursion In Java](http://www.baeldung.com/java-recursion)
|
||||
|
|
|
@ -16,5 +16,5 @@
|
|||
- [Delegated Properties in Kotlin](http://www.baeldung.com/kotlin-delegated-properties)
|
||||
- [Sealed Classes in Kotlin](http://www.baeldung.com/kotlin-sealed-classes)
|
||||
- [JUnit 5 for Kotlin Developers](http://www.baeldung.com/junit-5-kotlin)
|
||||
|
||||
- [Extension Methods in Kotlin](http://www.baeldung.com/kotlin-extension-methods)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
## Relevant articles:
|
||||
|
||||
- [Intro to Dubbo](http://www.baeldung.com/dubbo-intro)
|
||||
- [Introduction to Dubbo](http://www.baeldung.com/dubbo)
|
||||
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
### Relevant Articles:
|
||||
- [Database Migrations with Flyway](http://www.baeldung.com/database-migrations-with-flyway)
|
||||
- [A Guide to Flyway Callbacks](http://www.baeldung.com/flyway-callbacks)
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
## Relevant articles:
|
||||
- [Introduction to Gradle](http://www.baeldung.com/gradle)
|
||||
- [Writing Custom Gradle Plugins](http://www.baeldung.com/gradle-create-plugin)
|
||||
- [Creating a Fat Jar in Gradle](http://www.baeldung.com/gradle-fat-jar)
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
## Building
|
||||
|
||||
To build the module, use Maven's `package` goal:
|
||||
|
||||
```
|
||||
mvn clean package
|
||||
```
|
||||
|
||||
The `war` file will be available at `target/deep-jsf.war`
|
||||
|
||||
## Running
|
||||
|
||||
The `war` application is deployed to a Java EE 7 compliant application server, for example, to GlassFish 4 or later.
|
||||
|
||||
The example then will be accessible at http://localhost:8080/deep-jsf/index.xhtml
|
|
@ -0,0 +1,40 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.stackify</groupId>
|
||||
<artifactId>deep-jsf</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<packaging>war</packaging>
|
||||
|
||||
<properties>
|
||||
<failOnMissingWebXml>false</failOnMissingWebXml>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax</groupId>
|
||||
<artifactId>javaee-api</artifactId>
|
||||
<version>7.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>deep-jsf</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.7.0</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,14 @@
|
|||
package com.stackify.deepjsf;
|
||||
|
||||
import javax.faces.bean.ManagedBean;
|
||||
import javax.faces.bean.RequestScoped;
|
||||
|
||||
@ManagedBean
|
||||
@RequestScoped
|
||||
public class GreetControllerBean {
|
||||
|
||||
public String greet() {
|
||||
return "greet";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package com.stackify.deepjsf;
|
||||
|
||||
import javax.faces.bean.ManagedBean;
|
||||
import javax.faces.bean.RequestScoped;
|
||||
import javax.faces.component.UIComponent;
|
||||
import javax.faces.component.UIViewRoot;
|
||||
import javax.faces.component.visit.VisitContext;
|
||||
import javax.faces.component.visit.VisitResult;
|
||||
import javax.faces.event.PhaseEvent;
|
||||
import javax.faces.event.PhaseId;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@ManagedBean
|
||||
@RequestScoped
|
||||
public class PhaseListenerBean {
|
||||
|
||||
public void beforeListener(PhaseEvent event) {
|
||||
if (!event.getPhaseId().equals(PhaseId.RENDER_RESPONSE)) {
|
||||
return;
|
||||
}
|
||||
UIViewRoot root = event.getFacesContext().getViewRoot();
|
||||
|
||||
boolean showNewFeature = showNewFeatureForIp(event);
|
||||
|
||||
processComponentTree(root, event, showNewFeature);
|
||||
}
|
||||
|
||||
private boolean showNewFeatureForIp(PhaseEvent event) {
|
||||
HttpServletRequest request = (HttpServletRequest) event.getFacesContext()
|
||||
.getExternalContext().getRequest();
|
||||
String ip = request.getRemoteAddr();
|
||||
return !ip.startsWith("127.0");
|
||||
}
|
||||
|
||||
private void processComponentTree(UIComponent component, PhaseEvent event, boolean show) {
|
||||
component.visitTree(VisitContext.createVisitContext(event.getFacesContext()),
|
||||
(context, target) -> {
|
||||
if (target.getId() != null
|
||||
&& target.getId().startsWith("new-feature-")
|
||||
&& !show) {
|
||||
target.setRendered(false);
|
||||
}
|
||||
return VisitResult.ACCEPT;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package com.stackify.deepjsf;
|
||||
|
||||
import javax.faces.bean.ManagedBean;
|
||||
import javax.faces.bean.SessionScoped;
|
||||
import javax.faces.event.ValueChangeEvent;
|
||||
|
||||
@ManagedBean
|
||||
@SessionScoped
|
||||
public class UserBean {
|
||||
|
||||
private String name = "";
|
||||
|
||||
private String lastName = "";
|
||||
|
||||
private String proposedLogin = "";
|
||||
|
||||
public void nameChanged(ValueChangeEvent event) {
|
||||
this.proposedLogin = event.getNewValue() + "-" + lastName;
|
||||
}
|
||||
|
||||
public void lastNameChanged(ValueChangeEvent event) {
|
||||
this.proposedLogin = name + "-" + event.getNewValue();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public String getProposedLogin() {
|
||||
return proposedLogin;
|
||||
}
|
||||
|
||||
public void setProposedLogin(String proposedLogin) {
|
||||
this.proposedLogin = proposedLogin;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.stackify.deepjsf;
|
||||
|
||||
import javax.faces.bean.ManagedBean;
|
||||
import javax.faces.bean.RequestScoped;
|
||||
|
||||
@ManagedBean
|
||||
@RequestScoped
|
||||
public class UserControllerBean {
|
||||
|
||||
public String register() {
|
||||
return "register-success";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<faces-config version="2.2" 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-facesconfig_2_2.xsd">
|
||||
|
||||
<navigation-rule>
|
||||
<from-view-id>/register.xhtml</from-view-id>
|
||||
<navigation-case>
|
||||
<from-outcome>register-success</from-outcome>
|
||||
<to-view-id>/hello.xhtml</to-view-id>
|
||||
</navigation-case>
|
||||
</navigation-rule>
|
||||
|
||||
</faces-config>
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||
xmlns:f="http://xmlns.jcp.org/jsf/core">
|
||||
<f:view beforePhase="#{phaseListenerBean.beforeListener}">
|
||||
<h:outputLabel value="Hello, #{userBean.name}"/>
|
||||
<h:outputLabel id="new-feature-last-name" value=" #{userBean.lastName}"/>
|
||||
</f:view>
|
||||
</html>
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||
xmlns:f="http://xmlns.jcp.org/jsf/core">
|
||||
<f:view>
|
||||
<h:outputLabel value="Hello, #{userBean.name} #{userBean.lastName}! Your login is: #{userBean.proposedLogin}"/>
|
||||
</f:view>
|
||||
</html>
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||
xmlns:f="http://xmlns.jcp.org/jsf/core">
|
||||
<f:view beforePhase="#{phaseListenerBean.beforeListener}">
|
||||
<h:form>
|
||||
<h:panelGrid columns="2">
|
||||
<h:outputLabel value="First Name:"/>
|
||||
<h:inputText id="name" value="#{userBean.name}"/>
|
||||
<h:outputLabel id="new-feature-last-name-label" value="Last Name:"/>
|
||||
<h:inputText id="new-feature-last-name" value="#{userBean.lastName}"/>
|
||||
<h:commandButton value="Submit" action="#{greetControllerBean.greet}"/>
|
||||
</h:panelGrid>
|
||||
</h:form>
|
||||
</f:view>
|
||||
</html>
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||
xmlns:f="http://xmlns.jcp.org/jsf/core">
|
||||
|
||||
<h:head>
|
||||
<h:outputScript library="javax.faces" name="jsf.js"/>
|
||||
</h:head>
|
||||
|
||||
<f:view>
|
||||
<h:form>
|
||||
<h:panelGrid columns="2">
|
||||
<h:outputLabel value="First Name:"/>
|
||||
<h:inputText id="name" value="#{userBean.name}"
|
||||
valueChangeListener="#{userBean.nameChanged}">
|
||||
<f:ajax event="change" execute="@this" render="proposed-login"/>
|
||||
</h:inputText>
|
||||
<h:outputLabel id="lastname-label" value="Last Name:"/>
|
||||
<h:inputText id="lastname" value="#{userBean.lastName}"
|
||||
valueChangeListener="#{userBean.lastNameChanged}">
|
||||
<f:ajax event="change" execute="@this" render="proposed-login"/>
|
||||
</h:inputText>
|
||||
<h:outputLabel id="login-label" value="Proposed Login:"/>
|
||||
<h:inputText id="proposed-login" disabled="true" value="#{userBean.proposedLogin}"/>
|
||||
<h:commandButton value="Submit" action="#{userControllerBean.register}"/>
|
||||
</h:panelGrid>
|
||||
</h:form>
|
||||
</f:view>
|
||||
</html>
|
|
@ -5,3 +5,5 @@
|
|||
- [Hibernate – Mapping Date and Time](http://www.baeldung.com/hibernate-date-time)
|
||||
- [Hibernate Inheritance Mapping](http://www.baeldung.com/hibernate-inheritance)
|
||||
- [A Guide to Multitenancy in Hibernate 5](http://www.baeldung.com/hibernate-5-multitenancy)
|
||||
- [Introduction to Hibernate Spatial](http://www.baeldung.com/hibernate-spatial)
|
||||
- [Hibernate Interceptors](http://www.baeldung.com/hibernate-interceptor)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
### Relevant Article:
|
||||
- [Introduction to using InfluxDB with Java](http://www.baeldung.com/using-influxdb-with-java/)
|
||||
- [Using InfluxDB with Java](http://www.baeldung.com/java-influxdb)
|
||||
|
||||
### Overview
|
||||
This Maven project contains the Java code for the article linked above.
|
||||
|
|
|
@ -38,4 +38,9 @@ $ curl -X POST -H "Content-Type:application/json" -d '{ "firstName" : "Dassi", "
|
|||
|
||||
Now with default configurations it will be available at: [http://localhost:8080](http://localhost:8080)
|
||||
|
||||
Enjoy it :)
|
||||
Enjoy it :)
|
||||
|
||||
### Relevant Articles:
|
||||
|
||||
- [Intro to Performance Testing using JMeter](http://www.baeldung.com/jmeter)
|
||||
- [Configure Jenkins to Run and Show JMeter Tests](http://www.baeldung.com/jenkins-and-jmeter)
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
- [Introduction to Reladomo](http://www.baeldung.com/reladomo)
|
||||
- [Introduction to ORMLite](http://www.baeldung.com/ormlite)
|
||||
- [Introduction To Kryo](http://www.baeldung.com/kryo)
|
||||
- [Introduction to KafkaStreams in Java](http://www.baeldung.com/java-kafka-streams)
|
||||
|
|
|
@ -58,6 +58,8 @@
|
|||
- [Introduction to BouncyCastle with Java](http://www.baeldung.com/java-bouncy-castle)
|
||||
- [Intro to JDO Queries 2/2](http://www.baeldung.com/jdo-queries)
|
||||
- [Guide to google-http-client](http://www.baeldung.com/google-http-client)
|
||||
- [Interact with Google Sheets from Java](http://www.baeldung.com/google-sheets-java-client)
|
||||
|
||||
|
||||
|
||||
The libraries module contains examples related to small libraries that are relatively easy to use and does not require any separate module of its own.
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
|
||||
## Logging Modules
|
||||
|
||||
### Relevant Articles:
|
||||
|
||||
- [Creating a Custom Logback Appender](http://www.baeldung.com/custom-logback-appender)
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
### Relevant Articles:
|
||||
|
||||
- [Introduction to Apache Lucene](http://www.baeldung.com/lucene)
|
||||
- [A Simple File Search with Lucene](http://www.baeldung.com/lucene-file-search)
|
|
@ -0,0 +1,3 @@
|
|||
### Relevant Articles:
|
||||
|
||||
- [Getting Started With Mule ESB](http://www.baeldung.com/mule-esb)
|
|
@ -22,4 +22,7 @@ $ mvn clean install
|
|||
Before launching unit tests:
|
||||
- Install OrientDB
|
||||
- Create BaeldungDB, BaeldungDBTwo and BaeldungDBThree databases
|
||||
- Uncomment annotations on the test files
|
||||
- Uncomment annotations on the test files
|
||||
|
||||
### Relevant Articles:
|
||||
- [Introduction to the OrientDB Java APIs](http://www.baeldung.com/java-orientdb)
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
|
||||
## Persistence Modules
|
||||
|
||||
|
||||
### Relevant Articles:
|
||||
|
||||
- [Introduction to Hibernate Search](http://www.baeldung.com/hibernate-search)
|
||||
|
|
|
@ -30,6 +30,10 @@
|
|||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.thymeleaf.extras</groupId>
|
||||
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- oauth2 -->
|
||||
<dependency>
|
||||
|
@ -40,6 +44,21 @@
|
|||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-oauth2-jose</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
package com.baeldung.securityextrafields;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
|
||||
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
|
||||
|
||||
public static final String SPRING_SECURITY_FORM_DOMAIN_KEY = "domain";
|
||||
|
||||
@Override
|
||||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
|
||||
throws AuthenticationException {
|
||||
|
||||
if (!request.getMethod()
|
||||
.equals("POST")) {
|
||||
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
|
||||
}
|
||||
|
||||
UsernamePasswordAuthenticationToken authRequest = getAuthRequest(request);
|
||||
setDetails(request, authRequest);
|
||||
return this.getAuthenticationManager()
|
||||
.authenticate(authRequest);
|
||||
}
|
||||
|
||||
private UsernamePasswordAuthenticationToken getAuthRequest(HttpServletRequest request) {
|
||||
String username = obtainUsername(request);
|
||||
String password = obtainPassword(request);
|
||||
String domain = obtainDomain(request);
|
||||
|
||||
if (username == null) {
|
||||
username = "";
|
||||
}
|
||||
if (password == null) {
|
||||
password = "";
|
||||
}
|
||||
if (domain == null) {
|
||||
domain = "";
|
||||
}
|
||||
|
||||
String usernameDomain = String.format("%s%s%s", username.trim(),
|
||||
String.valueOf(Character.LINE_SEPARATOR), domain);
|
||||
return new UsernamePasswordAuthenticationToken(usernameDomain, password);
|
||||
}
|
||||
|
||||
private String obtainDomain(HttpServletRequest request) {
|
||||
return request.getParameter(SPRING_SECURITY_FORM_DOMAIN_KEY);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package com.baeldung.securityextrafields;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service("userDetailsService")
|
||||
public class CustomUserDetailsService implements UserDetailsService {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
||||
public CustomUserDetailsService(UserRepository userRepository) {
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
String[] usernameAndDomain = StringUtils.split(username, String.valueOf(Character.LINE_SEPARATOR));
|
||||
if (usernameAndDomain == null || usernameAndDomain.length != 2) {
|
||||
throw new UsernameNotFoundException("Username and domain must be provided");
|
||||
}
|
||||
User user = userRepository.findUser(usernameAndDomain[0], usernameAndDomain[1]);
|
||||
if (user == null) {
|
||||
throw new UsernameNotFoundException(
|
||||
String.format("Username not found for domain, username=%s, domain=%s",
|
||||
usernameAndDomain[0], usernameAndDomain[1]));
|
||||
}
|
||||
return user;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.baeldung.securityextrafields;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository("userRepository")
|
||||
public class CustomUserRepository implements UserRepository {
|
||||
|
||||
@Override
|
||||
public User findUser(String username, String domain) {
|
||||
if (StringUtils.isAnyBlank(username, domain)) {
|
||||
return null;
|
||||
} else {
|
||||
Collection<? extends GrantedAuthority> authorities = new ArrayList<>();
|
||||
User user = new User(username, domain,
|
||||
"$2a$10$U3GhSMpsMSOE8Kqsbn58/edxDBKlVuYMh7qk/7ErApYFjJzi2VG5K", true,
|
||||
true, true, true, authorities);
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package com.baeldung.securityextrafields;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||
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;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
|
||||
@EnableWebSecurity
|
||||
@PropertySource("classpath:/application-extrafields.properties")
|
||||
public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Autowired
|
||||
private UserDetailsService userDetailsService;
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
|
||||
http
|
||||
.addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter.class)
|
||||
.authorizeRequests()
|
||||
.antMatchers("/css/**", "/index").permitAll()
|
||||
.antMatchers("/user/**").authenticated()
|
||||
.and()
|
||||
.formLogin().loginPage("/login")
|
||||
.and()
|
||||
.logout()
|
||||
.logoutUrl("/logout");
|
||||
}
|
||||
|
||||
public CustomAuthenticationFilter authenticationFilter() throws Exception {
|
||||
CustomAuthenticationFilter filter = new CustomAuthenticationFilter();
|
||||
filter.setAuthenticationManager(authenticationManagerBean());
|
||||
filter.setAuthenticationFailureHandler(failureHandler());
|
||||
return filter;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.authenticationProvider(authProvider());
|
||||
}
|
||||
|
||||
public AuthenticationProvider authProvider() {
|
||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||
provider.setUserDetailsService(userDetailsService);
|
||||
provider.setPasswordEncoder(passwordEncoder());
|
||||
return provider;
|
||||
}
|
||||
|
||||
public SimpleUrlAuthenticationFailureHandler failureHandler() {
|
||||
return new SimpleUrlAuthenticationFailureHandler("/login?error=true");
|
||||
}
|
||||
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.baeldung.securityextrafields;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SpringExtraLoginFieldsApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringExtraLoginFieldsApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.baeldung.securityextrafields;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
|
||||
public class User extends org.springframework.security.core.userdetails.User {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String domain;
|
||||
|
||||
public User(String username, String domain, String password, boolean enabled,
|
||||
boolean accountNonExpired, boolean credentialsNonExpired,
|
||||
boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
|
||||
super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
|
||||
this.domain = domain;
|
||||
}
|
||||
|
||||
public String getDomain() {
|
||||
return domain;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.baeldung.securityextrafields;
|
||||
|
||||
public interface UserRepository {
|
||||
|
||||
public User findUser(String username, String domain);
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package com.baeldung.securityextrafields;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
@Controller
|
||||
public class WebController {
|
||||
|
||||
@RequestMapping("/")
|
||||
public String root() {
|
||||
return "redirect:/index";
|
||||
}
|
||||
|
||||
@RequestMapping("/index")
|
||||
public String index(Model model) {
|
||||
getDomain().ifPresent(d -> {
|
||||
model.addAttribute("domain", d);
|
||||
});
|
||||
return "index";
|
||||
}
|
||||
|
||||
@RequestMapping("/user/index")
|
||||
public String userIndex(Model model) {
|
||||
getDomain().ifPresent(d -> {
|
||||
model.addAttribute("domain", d);
|
||||
});
|
||||
return "user/index";
|
||||
}
|
||||
|
||||
@RequestMapping("/login")
|
||||
public String login() {
|
||||
return "login";
|
||||
}
|
||||
|
||||
private Optional<String> getDomain() {
|
||||
Authentication auth = SecurityContextHolder.getContext()
|
||||
.getAuthentication();
|
||||
String domain = null;
|
||||
if (auth != null && !auth.getClass().equals(AnonymousAuthenticationToken.class)) {
|
||||
User user = (User) auth.getPrincipal();
|
||||
domain = user.getDomain();
|
||||
}
|
||||
return Optional.ofNullable(domain);
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
spring.thymeleaf.prefix = classpath:/templatesextrafields/
|
|
@ -0,0 +1,18 @@
|
|||
body {
|
||||
font-family: sans;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
p.error {
|
||||
font-weight: bold;
|
||||
color: red;
|
||||
}
|
||||
|
||||
div.logout {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.formfield {
|
||||
margin: 0.5em;
|
||||
padding: 0.3em;
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
|
||||
<head>
|
||||
<title>Spring Security - Login With Extra Fields</title>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" />
|
||||
</head>
|
||||
<body>
|
||||
<div th:fragment="logout" class="logout" sec:authorize="isAuthenticated()">
|
||||
Logged in user: <span sec:authentication="name"></span> |
|
||||
domain: <span th:text="${domain}">Some Domain</span>
|
||||
<div>
|
||||
<form action="#" th:action="@{/logout}" method="post">
|
||||
<input type="submit" value="Logout" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<h1>Hello Spring Security</h1>
|
||||
<p>This is an unsecured page, but you can access the secured pages after authenticating.</p>
|
||||
<ul>
|
||||
<li>Go to the <a href="/user/index" th:href="@{/user/index}">secured pages</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<title>Login page</title>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Login page</h1>
|
||||
<p>Example: user / domain / password</p>
|
||||
<p th:if="${param.error}" class="error">Invalid user, password, or domain</p>
|
||||
<form th:action="@{/login}" method="post">
|
||||
<label for="username">Username</label>:
|
||||
<input class="formfield" type="text" id="username" name="username" autofocus="autofocus" /> <br />
|
||||
<label for="domain">Domain</label>:
|
||||
<input class="formfield" type="text" id="domain" name="domain" /> <br />
|
||||
<label for="password">Password</label>:
|
||||
<input class="formfield" type="password" id="password" name="password" /> <br />
|
||||
<input type="submit" value="Log in" />
|
||||
</form>
|
||||
<p><a href="/index" th:href="@{/index}">Back to home page</a></p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<title>Spring Security - Login With Extra Fields</title>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" />
|
||||
</head>
|
||||
<body>
|
||||
<div th:replace="index::logout"></div>
|
||||
<h1>This is a secured page!</h1>
|
||||
<p><a href="/index" th:href="@{/index}">Back to home page</a></p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,103 @@
|
|||
package com.baeldung.securityextrafields;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
|
||||
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrlPattern;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.mock.web.MockHttpSession;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||
import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringJUnitWebConfig
|
||||
@SpringBootTest(classes = SpringExtraLoginFieldsApplication.class)
|
||||
public class SecurityExtraFieldsTest {
|
||||
|
||||
@Autowired
|
||||
private FilterChainProxy springSecurityFilterChain;
|
||||
|
||||
@Autowired
|
||||
private WebApplicationContext wac;
|
||||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.mockMvc = MockMvcBuilders.webAppContextSetup(wac)
|
||||
.apply(springSecurity(springSecurityFilterChain)).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenRootPathAccess_thenRedirectToIndex() throws Exception {
|
||||
this.mockMvc.perform(get("/"))
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andExpect(redirectedUrlPattern("/index*"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenSecuredResource_whenAccessUnauthenticated_thenRequiresAuthentication() throws Exception {
|
||||
this.mockMvc.perform(get("/user/index"))
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andExpect(redirectedUrlPattern("**/login"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAccessSecuredResource_whenAuthenticated_thenAuthHasExtraFields() throws Exception {
|
||||
MockHttpServletRequestBuilder securedResourceAccess = get("/user/index");
|
||||
MvcResult unauthenticatedResult = mockMvc.perform(securedResourceAccess)
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andReturn();
|
||||
|
||||
MockHttpSession session = (MockHttpSession) unauthenticatedResult.getRequest()
|
||||
.getSession();
|
||||
String loginUrl = unauthenticatedResult.getResponse()
|
||||
.getRedirectedUrl();
|
||||
|
||||
User user = getUser();
|
||||
|
||||
mockMvc.perform(post(loginUrl)
|
||||
.param("username", user.getUsername())
|
||||
.param("password", user.getPassword())
|
||||
.param("domain", user.getDomain())
|
||||
.session(session)
|
||||
.with(csrf()))
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andExpect(redirectedUrlPattern("**/user/index"))
|
||||
.andReturn();
|
||||
|
||||
mockMvc.perform(securedResourceAccess.session(session))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
SecurityContext securityContext
|
||||
= (SecurityContext) session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
|
||||
Authentication auth = securityContext.getAuthentication();
|
||||
assertEquals(((User)auth.getPrincipal()).getDomain(), user.getDomain());
|
||||
}
|
||||
|
||||
private User getUser() {
|
||||
Collection<? extends GrantedAuthority> authorities = new ArrayList<>();
|
||||
return new User("myusername", "mydomain", "password", true, true, true, true, authorities);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -19,4 +19,6 @@
|
|||
|
||||
### Relevant Articles:
|
||||
- [Introduction to Spring Cloud Rest Client with Netflix Ribbon](http://www.baeldung.com/spring-cloud-rest-client-with-netflix-ribbon)
|
||||
[An Introduction to Spring Cloud Zookeeper](http://www.baeldung.com/spring-cloud-zookeeper)
|
||||
- [An Introduction to Spring Cloud Zookeeper](http://www.baeldung.com/spring-cloud-zookeeper)
|
||||
- [Spring Cloud Connectors and Heroku](http://www.baeldung.com/spring-cloud-heroku)
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
# README #
|
||||
|
||||
This README would normally document whatever steps are necessary to get your application up and running.
|
||||
|
||||
### What is this repository for? ###
|
||||
|
||||
* Quick summary
|
||||
* Version
|
||||
* [Learn Markdown](https://bitbucket.org/tutorials/markdowndemo)
|
||||
|
||||
### How do I get set up? ###
|
||||
|
||||
* Summary of set up
|
||||
* Configuration
|
||||
* Dependencies
|
||||
* Database configuration
|
||||
* How to run tests
|
||||
* Deployment instructions
|
||||
|
||||
### Contribution guidelines ###
|
||||
|
||||
* Writing tests
|
||||
* Code review
|
||||
* Other guidelines
|
||||
|
||||
### Who do I talk to? ###
|
||||
|
||||
* Repo owner or admin
|
||||
* Other community or team contact
|
|
@ -0,0 +1,28 @@
|
|||
myauthkey
|
||||
|
||||
|
||||
security:
|
||||
oauth2:
|
||||
resource:
|
||||
jwt:
|
||||
keyValue: |
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjj4JDMgT4OoaXisEd8Nz
|
||||
uiLwum9mh8BH1l9Atpe+uZkepf3Vnv0Bhxn0BGR+kYGwEHZPVpWsHEyTfIRdinaQ
|
||||
vlPaxWJquQW25yYstrCuQTKJvFjSO/cX/V4OGi1RUj76mOpwzkm1Kui3R7Sfh8Zo
|
||||
WO0GiWIFJqNBsZ9b1wOfBMXnge+A+u/qxVNnTFpwCVj6k2Yb4YUsmLNCmND7E3Ra
|
||||
BnrNQWqMU2numhV+ADpmVH08m/+pWdZ896uYu/tvQnz3agvZPcFsEst7LcNAWQFT
|
||||
eNLkfwVfepKWa9jPELemtTLf1MkMppU+Lj1UNCr8x4Y6EupRDZhplVNtqYsPNDpO
|
||||
7wIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
|
||||
|
||||
|
||||
jwt:
|
||||
certificate:
|
||||
store:
|
||||
file: classpath:/certificate/my-auth-server.jks
|
||||
password: storepassword
|
||||
key:
|
||||
alias: myauthserver
|
||||
password: keypassword
|
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>authserver</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>1.5.9.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-oauth2</artifactId>
|
||||
<version>1.1.2.RELEASE</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,12 @@
|
|||
package com.baeldung;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.*;
|
||||
|
||||
@SpringBootApplication
|
||||
public class AuthServer {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(AuthServer.class, args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package com.baeldung.config;
|
||||
|
||||
import java.security.KeyPair;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
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.configuration.EnableAuthorizationServer;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
|
||||
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
|
||||
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
|
||||
|
||||
@Configuration
|
||||
@EnableAuthorizationServer
|
||||
@Order(6)
|
||||
public class AuthServerConfigurer
|
||||
extends
|
||||
AuthorizationServerConfigurerAdapter {
|
||||
|
||||
@Value("${jwt.certificate.store.file}")
|
||||
private Resource keystore;
|
||||
|
||||
@Value("${jwt.certificate.store.password}")
|
||||
private String keystorePassword;
|
||||
|
||||
@Value("${jwt.certificate.key.alias}")
|
||||
private String keyAlias;
|
||||
|
||||
@Value("${jwt.certificate.key.password}")
|
||||
private String keyPassword;
|
||||
|
||||
@Autowired
|
||||
private UserDetailsService userDetailsService;
|
||||
|
||||
@Override
|
||||
public void configure(
|
||||
ClientDetailsServiceConfigurer clients)
|
||||
throws Exception {
|
||||
clients
|
||||
.inMemory()
|
||||
.withClient("authserver")
|
||||
.secret("passwordforauthserver")
|
||||
.redirectUris("http://localhost:8080/")
|
||||
.authorizedGrantTypes("authorization_code",
|
||||
"refresh_token")
|
||||
.scopes("myscope")
|
||||
.autoApprove(true)
|
||||
.accessTokenValiditySeconds(30)
|
||||
.refreshTokenValiditySeconds(1800);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(
|
||||
AuthorizationServerEndpointsConfigurer endpoints)
|
||||
throws Exception {
|
||||
endpoints
|
||||
.accessTokenConverter(jwtAccessTokenConverter())
|
||||
.userDetailsService(userDetailsService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JwtAccessTokenConverter jwtAccessTokenConverter() {
|
||||
KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(
|
||||
keystore, keystorePassword.toCharArray());
|
||||
KeyPair keyPair = keyStoreKeyFactory.getKeyPair(
|
||||
keyAlias, keyPassword.toCharArray());
|
||||
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
|
||||
converter.setKeyPair(keyPair);
|
||||
return converter;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package com.baeldung.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
|
||||
|
||||
/**
|
||||
* Our configuration for the OAuth2 User Info Resource Server.
|
||||
*/
|
||||
@Configuration
|
||||
@EnableResourceServer
|
||||
public class ResourceServerConfigurer extends ResourceServerConfigurerAdapter {
|
||||
@Override
|
||||
public void configure(HttpSecurity http) throws Exception {
|
||||
http.antMatcher("/user")
|
||||
.authorizeRequests()
|
||||
.anyRequest()
|
||||
.authenticated();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.baeldung.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
|
||||
@Configuration
|
||||
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
registry.addViewController("login").setViewName("login");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package com.baeldung.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
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;
|
||||
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableOAuth2Client
|
||||
public class WebSecurityConfigurer
|
||||
extends
|
||||
WebSecurityConfigurerAdapter {
|
||||
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http)
|
||||
throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.antMatchers("/login**").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
.and().csrf()
|
||||
.and().formLogin().loginPage("/login");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(
|
||||
AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("user")
|
||||
.roles("USER")
|
||||
.and()
|
||||
.withUser("admin").password("admin")
|
||||
.roles("USER", "ADMIN");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Bean(name = "userDetailsService")
|
||||
public UserDetailsService userDetailsServiceBean()
|
||||
throws Exception {
|
||||
return super.userDetailsServiceBean();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.baeldung.controller;
|
||||
|
||||
import java.security.Principal;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* Because this application is also a User Info Resource Server, we expose info about the logged in user at:
|
||||
*
|
||||
* http://localhost:9090/auth/user
|
||||
*/
|
||||
@RestController
|
||||
public class ResourceController {
|
||||
|
||||
@RequestMapping("/user")
|
||||
public Principal user(Principal user) {
|
||||
return user;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
# Make the application available at http://localhost:7070/authserver
|
||||
server:
|
||||
port: 7070
|
||||
contextPath: /authserver
|
||||
|
||||
# Our certificate settings for enabling JWT tokens
|
||||
jwt:
|
||||
certificate:
|
||||
store:
|
||||
file: classpath:/certificate/mykeystore.jks
|
||||
password: abirkhan04
|
||||
key:
|
||||
alias: myauthkey
|
||||
password: abirkhan04
|
||||
|
||||
|
||||
security:
|
||||
oauth2:
|
||||
resource:
|
||||
filter-order: 3
|
||||
|
Binary file not shown.
|
@ -0,0 +1,29 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<title>Baeldung Spring cloud Security</title>
|
||||
</head>
|
||||
<body onload="document.f.username.focus();">
|
||||
|
||||
<h1>Login</h1>
|
||||
|
||||
|
||||
<form th:action="@{/login}" name="f" method="post">
|
||||
<fieldset>
|
||||
<h2> Username and Password:</h2>
|
||||
<p>
|
||||
<label for="username">Username</label>
|
||||
<input type="text" id="username" name="username"/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="password">Password</label>
|
||||
<input type="password" id="password" name="password"/>
|
||||
</p>
|
||||
<p>
|
||||
<input name="submit" type="submit" value="Login"/>
|
||||
</p>
|
||||
</fieldset>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
Binary file not shown.
|
@ -0,0 +1,102 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>oauth2client</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>oauth2client</name>
|
||||
<description>Demo project for Spring Boot</description>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>1.5.9.RELEASE</version>
|
||||
<relativePath /> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-dependencies</artifactId>
|
||||
<version>Dalston.SR4</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
||||
|
||||
<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-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-oauth2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-zuul</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.webjars</groupId>
|
||||
<artifactId>jquery</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.webjars</groupId>
|
||||
<artifactId>bootstrap</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.webjars</groupId>
|
||||
<artifactId>webjars-locator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.webjars</groupId>
|
||||
<artifactId>js-cookie</artifactId>
|
||||
<version>2.1.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,22 @@
|
|||
package com.baeldung;
|
||||
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
import com.baeldung.filters.SimpleFilter;
|
||||
|
||||
|
||||
@SpringBootApplication
|
||||
public class CloudSite {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(CloudSite.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SimpleFilter simpleFilter() {
|
||||
return new SimpleFilter();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package com.baeldung.config;
|
||||
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
|
||||
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.oauth2.client.OAuth2ClientContext;
|
||||
import org.springframework.security.oauth2.client.OAuth2RestOperations;
|
||||
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
|
||||
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
|
||||
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
|
||||
|
||||
@EnableZuulProxy
|
||||
@Configuration
|
||||
@EnableOAuth2Sso
|
||||
public class SiteSecurityConfigurer
|
||||
extends
|
||||
WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http)
|
||||
throws Exception {
|
||||
http.antMatcher("/**")
|
||||
.authorizeRequests()
|
||||
.antMatchers("/", "/webjars/**")
|
||||
.permitAll()
|
||||
.anyRequest()
|
||||
.authenticated()
|
||||
.and()
|
||||
.logout()
|
||||
.logoutSuccessUrl("/")
|
||||
.permitAll()
|
||||
.and()
|
||||
.csrf()
|
||||
.csrfTokenRepository(
|
||||
CookieCsrfTokenRepository
|
||||
.withHttpOnlyFalse());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public OAuth2RestOperations restOperations(
|
||||
OAuth2ProtectedResourceDetails resource,
|
||||
OAuth2ClientContext context) {
|
||||
return new OAuth2RestTemplate(resource, context);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package com.baeldung.controller;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
@RestController
|
||||
public class CloudSiteController {
|
||||
|
||||
@Autowired
|
||||
private RestOperations restOperations;
|
||||
|
||||
@GetMapping("/")
|
||||
@ResponseBody
|
||||
public String helloFromBaeldung() {
|
||||
return "Hello From Baeldung!";
|
||||
}
|
||||
|
||||
@GetMapping("/person")
|
||||
public ModelAndView person() {
|
||||
ModelAndView mav = new ModelAndView("personinfo");
|
||||
String personResourceUrl = "http://localhost:9000/personResource";
|
||||
mav.addObject("person", restOperations.getForObject(personResourceUrl, String.class));
|
||||
return mav;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package com.baeldung.filters;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import com.netflix.zuul.context.RequestContext;
|
||||
import com.netflix.zuul.ZuulFilter;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class SimpleFilter extends ZuulFilter {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(SimpleFilter.class);
|
||||
|
||||
@Override
|
||||
public String filterType() {
|
||||
return "pre";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int filterOrder() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldFilter() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object run() {
|
||||
RequestContext ctx = RequestContext.getCurrentContext();
|
||||
HttpServletRequest request = ctx.getRequest();
|
||||
|
||||
log.info(String.format("%s request to %s", request.getMethod(), request.getRequestURL().toString()));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
# Make the application available at http://localhost:8080
|
||||
# These are default settings, but we add them for clarity.
|
||||
server:
|
||||
port: 8080
|
||||
contextPath: /
|
||||
|
||||
# Configure the Authorization Server and User Info Resource Server details
|
||||
security:
|
||||
oauth2:
|
||||
client:
|
||||
accessTokenUri: http://localhost:7070/authserver/oauth/token
|
||||
userAuthorizationUri: http://localhost:7070/authserver/oauth/authorize
|
||||
clientId: authserver
|
||||
clientSecret: passwordforauthserver
|
||||
resource:
|
||||
userInfoUri: http://localhost:7070/authserver/user
|
||||
|
||||
person:
|
||||
url: http://localhost:9000/person
|
||||
|
||||
# Proxies the calls to http://localhost:8080/api/* to our REST service at http://localhost:8081/*
|
||||
# and automatically includes our OAuth2 token in the request headers
|
||||
zuul:
|
||||
routes:
|
||||
resource:
|
||||
path: /api/**
|
||||
url: http://localhost:9000
|
||||
user:
|
||||
path: /user/**
|
||||
url: http://localhost:7070/authserver/user
|
||||
|
||||
# Make sure the OAuth2 token is only relayed when using the internal API,
|
||||
# do not pass any authentication to the external API
|
||||
proxy:
|
||||
auth:
|
||||
routes:
|
||||
api: oauth2
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Getting Personal Information</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Providing Person Information</h1>
|
||||
<p>
|
||||
Person's information: <span id="personInfo" th:text="${person}"></span>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,16 @@
|
|||
package com.example.springoath2;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class Springoath2ApplicationTests {
|
||||
|
||||
@Test
|
||||
public void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>personresource</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>personresource</name>
|
||||
<description>Demo project for Spring Boot</description>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>1.5.9.RELEASE</version>
|
||||
<relativePath /> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
<spring-cloud.version>Edgware.RELEASE</spring-cloud.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security.oauth</groupId>
|
||||
<artifactId>spring-security-oauth2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-jwt</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-dependencies</artifactId>
|
||||
<version>${spring-cloud.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
</project>
|
|
@ -0,0 +1,12 @@
|
|||
package com.baeldung;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.baeldung.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
|
||||
|
||||
/**
|
||||
* REST API Resource Server.
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableResourceServer
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true) // Allow method annotations like @PreAuthorize
|
||||
public class ResourceConfigurer extends ResourceServerConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
public void configure(HttpSecurity http) throws Exception {
|
||||
http.httpBasic().disable();
|
||||
http.authorizeRequests().anyRequest().authenticated();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package com.baeldung.controller;
|
||||
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.baeldung.model.Person;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
@RestController
|
||||
public class PersonInfoController {
|
||||
|
||||
@GetMapping("/personResource")
|
||||
@PreAuthorize("hasAnyRole('ADMIN', 'USER')")
|
||||
public @ResponseBody String personInfo() {
|
||||
Gson gson = new Gson();
|
||||
String person = gson.toJson(new Person("abir", "Dhaka", "Bangladesh", 29, "Male"));
|
||||
return person;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package com.baeldung.model;
|
||||
|
||||
public class Person {
|
||||
|
||||
private String name;
|
||||
private String city;
|
||||
private String country;
|
||||
private Integer age;
|
||||
private String sex;
|
||||
|
||||
public Person(String name, String city, String country, Integer age, String sex) {
|
||||
this.name = name;
|
||||
this.city = city;
|
||||
this.country = country;
|
||||
this.age = age;
|
||||
this.sex = sex;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getCity() {
|
||||
return city;
|
||||
}
|
||||
|
||||
public void setCity(String city) {
|
||||
this.city = city;
|
||||
}
|
||||
|
||||
public String getCountry() {
|
||||
return country;
|
||||
}
|
||||
|
||||
public void setCountry(String country) {
|
||||
this.country = country;
|
||||
}
|
||||
|
||||
public Integer getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(Integer age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public String getSex() {
|
||||
return sex;
|
||||
}
|
||||
|
||||
public void setSex(String sex) {
|
||||
this.sex = sex;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
# Make the application available at http://localhost:9000
|
||||
|
||||
server:
|
||||
port: 9000
|
||||
|
||||
# Configure the public key to use for verifying the incoming JWT tokens
|
||||
security:
|
||||
sessions: NEVER
|
||||
oauth2:
|
||||
resource:
|
||||
userInfoUri: http://localhost:7070/authserver/user
|
||||
jwt:
|
||||
keyValue: |
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhiiifKv6Otf5PyqIE+LQ
|
||||
EiJRRh6q8piPY9Okq+RfRu9Bue0D8hq7aFxcgkLZ6Bg9CAS+w1KdaE5MMeOCVVxv
|
||||
rpRETzVpAsh6GL5nBc679jSqMzjr3V4uty46ilL4VHKSxlZh5Nmz5EMHPI5iwpNs
|
||||
8U5n3QiwsTk514FXad54xPSPH3i/pDzGSZHrVcwDVaOKn7gFiIqP86vkJB47JZv8
|
||||
T6P5RK7Rj06zoG45DMGWG3DQv6o1/Jm4IJQWj0AUD3bSHqzXkPr7qyMYvkE4kyMH
|
||||
6aVAsAYMxilZFlJMv2b8N883gdi3LEeOJo8zZr5IWyyROfepdeOL7UkAXddAj+dL
|
||||
WQIDAQAB
|
||||
-----END PUBLIC KEY-----
|
|
@ -0,0 +1,16 @@
|
|||
package com.baeldung.service.personservice;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class PersonserviceApplicationTests {
|
||||
|
||||
@Test
|
||||
public void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhiiifKv6Otf5PyqIE+LQ
|
||||
EiJRRh6q8piPY9Okq+RfRu9Bue0D8hq7aFxcgkLZ6Bg9CAS+w1KdaE5MMeOCVVxv
|
||||
rpRETzVpAsh6GL5nBc679jSqMzjr3V4uty46ilL4VHKSxlZh5Nmz5EMHPI5iwpNs
|
||||
8U5n3QiwsTk514FXad54xPSPH3i/pDzGSZHrVcwDVaOKn7gFiIqP86vkJB47JZv8
|
||||
T6P5RK7Rj06zoG45DMGWG3DQv6o1/Jm4IJQWj0AUD3bSHqzXkPr7qyMYvkE4kyMH
|
||||
6aVAsAYMxilZFlJMv2b8N883gdi3LEeOJo8zZr5IWyyROfepdeOL7UkAXddAj+dL
|
||||
WQIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDfzCCAmegAwIBAgIEDqsC7jANBgkqhkiG9w0BAQsFADBwMQswCQYDVQQGEwI4
|
||||
ODETMBEGA1UECBMKQmFuZ2xhZGVzaDEOMAwGA1UEBxMFRGhha2ExETAPBgNVBAoT
|
||||
CEJhZWxkdW5nMRUwEwYDVQQLEwxCYWVsZHVuZ2Jsb2cxEjAQBgNVBAMTCWxvY2Fs
|
||||
aG9zdDAeFw0xNzEyMjUxNDE0MDhaFw0xODAzMjUxNDE0MDhaMHAxCzAJBgNVBAYT
|
||||
Ajg4MRMwEQYDVQQIEwpCYW5nbGFkZXNoMQ4wDAYDVQQHEwVEaGFrYTERMA8GA1UE
|
||||
ChMIQmFlbGR1bmcxFTATBgNVBAsTDEJhZWxkdW5nYmxvZzESMBAGA1UEAxMJbG9j
|
||||
YWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhiiifKv6Otf5
|
||||
PyqIE+LQEiJRRh6q8piPY9Okq+RfRu9Bue0D8hq7aFxcgkLZ6Bg9CAS+w1KdaE5M
|
||||
MeOCVVxvrpRETzVpAsh6GL5nBc679jSqMzjr3V4uty46ilL4VHKSxlZh5Nmz5EMH
|
||||
PI5iwpNs8U5n3QiwsTk514FXad54xPSPH3i/pDzGSZHrVcwDVaOKn7gFiIqP86vk
|
||||
JB47JZv8T6P5RK7Rj06zoG45DMGWG3DQv6o1/Jm4IJQWj0AUD3bSHqzXkPr7qyMY
|
||||
vkE4kyMH6aVAsAYMxilZFlJMv2b8N883gdi3LEeOJo8zZr5IWyyROfepdeOL7UkA
|
||||
XddAj+dLWQIDAQABoyEwHzAdBgNVHQ4EFgQUHLFYkq36Wami5qsVRe/1eQedmdgw
|
||||
DQYJKoZIhvcNAQELBQADggEBABL3lYyuRd6Hv8DPus/zQL0bRl6gVsEzczwmWMUA
|
||||
3NJZbUHAD/KC732aArvKIKykkbLG6K/Mhnfuu8YBfWzTvGgY3Ww+ka2sJFOsUW7r
|
||||
sa6OBtNHh4zhDYN2Weza+4jnRLxtkzFbm6v2sheFkyB1NywCwFE/6p1Z6KTG8RyJ
|
||||
gw/OHl6rb+Y/T6cOeeTCFUN/v+qRVSB9I/MjSK5wRNbFT+MyNUeL6gsiyIvxSZbj
|
||||
y4vrjGHkXasSmwkfvgw67mJMk4XTGrVLjIXUTyzbdSmodcv8N6nrsIk4SBYCnTrI
|
||||
E/5NtNgbOFGwovde5yNrZIjjAC1VGOmVFhcxFJpwT6ZkSks=
|
||||
-----END CERTIFICATE-----
|
|
@ -21,12 +21,17 @@ public class EurekaClientApplication implements GreetingController {
|
|||
@Value("${spring.application.name}")
|
||||
private String appName;
|
||||
|
||||
@Value("${server.port}")
|
||||
private String portNumber;
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(EurekaClientApplication.class, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String greeting() {
|
||||
return String.format("Hello from '%s'!", eurekaClient.getApplication(appName).getName());
|
||||
System.out.println("Request received on port number " + portNumber);
|
||||
return String.format("Hello from '%s with Port Number %s'!", eurekaClient.getApplication(appName)
|
||||
.getName(), portNumber);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ spring:
|
|||
name: spring-cloud-eureka-client
|
||||
|
||||
server:
|
||||
port: 0
|
||||
port: 8081
|
||||
|
||||
eureka:
|
||||
client:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
### Relevant Articles
|
||||
|
||||
- [Integration Guide for Spring and EJB](http://www.baeldung.com/spring-ejb)
|
|
@ -4,11 +4,11 @@
|
|||
xmlns:mvc="http://www.springframework.org/schema/mvc"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
|
||||
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
|
||||
http://www.springframework.org/schema/context
|
||||
http://www.springframework.org/schema/context/spring-context-4.2.xsd
|
||||
http://www.springframework.org/schema/context/spring-context-4.3.xsd
|
||||
http://www.springframework.org/schema/mvc
|
||||
http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd">
|
||||
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd">
|
||||
|
||||
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" />
|
||||
<context:component-scan base-package="com.baeldung.spring.controller" />
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
xmlns:mvc="http://www.springframework.org/schema/mvc"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
|
||||
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
|
||||
http://www.springframework.org/schema/context
|
||||
http://www.springframework.org/schema/context/spring-context-4.2.xsd
|
||||
http://www.springframework.org/schema/context/spring-context-4.3.xsd
|
||||
http://www.springframework.org/schema/mvc
|
||||
http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd"
|
||||
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd"
|
||||
>
|
||||
|
||||
<mvc:annotation-driven>
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
|
||||
http://www.springframework.org/schema/mvc
|
||||
http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
|
||||
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
|
||||
|
||||
|
||||
<context:component-scan base-package="com.baeldung.spring.controller"/>
|
||||
|
@ -58,4 +58,4 @@
|
|||
<!-- End: Mapping by ControllerClassNameHandlerMapping with prefix -->
|
||||
|
||||
|
||||
</beans>
|
||||
</beans>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue