Skip to content
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ bin
.settings
.springBeans
.sts4-cache/
.attach_pid*
.DS_Store
*.sw*
*.iml
Expand All @@ -26,6 +27,7 @@ nbdist/
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.test.json
!.vscode/launch.json
!.vscode/extensions.json
node/
Expand Down
29 changes: 23 additions & 6 deletions basic/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ Once the Angular app is primed, your application will be loadable in a browser (
$ mvn spring-boot:run
----

and go to a browser at http://localhost:8080[http://localhost:8080]. When you load the home page you should get a browser dialog asking for username and password (the username is "user" and the password is printed in the console logs on startup). There's actually no content yet (or maybe the deafult "hero" tutorial content from the `ng` CLI), so you should get essentially a blank page.
and go to a browser at http://localhost:8080[http://localhost:8080]. When you load the home page you should get a whitelabel login page asking for username and password (the username is "user" and the password is printed in the console logs on startup). There's actually no content yet (or maybe the deafult "hero" tutorial content from the `ng` CLI), so you should get essentially a blank page.

TIP: If you don't like scraping the console log for the password just add this to the "application.properties" (in "src/main/resources"): `security.user.password=password` (and choose your own password). We did this in the sample code using "application.yml".
TIP: If you don't like scraping the console log for the password just add this to the "application.properties" (in "src/main/resources"): `spring.security.user.password=password` (and choose your own password). We did this in the sample code using "application.yml".

In an IDE, just run the `main()` method in the application class (there is only one class, and it is called `UiApplication` if you used the "curl" command above).

Expand Down Expand Up @@ -161,6 +161,27 @@ $ curl localhost:8080/resource
{"timestamp":1420442772928,"status":401,"error":"Unauthorized","message":"Full authentication is required to access this resource","path":"/resource"}
----

=== HTTP Basic Authentication

The curl command above returned a 401 response because the user agent was detected and Spring Security assumed that was a better response than a 302 redirect to the login page. We don't actually want the login page for our app. We could replace it with a nicer looking one, and we will be doing that later in the tutorial. For now, we want to just use HTTP Basic authentication, so we need to override the default Spring Security configuration. To do this we can add a `WebSecurityConfigurer` to the context and Spring Boot will back off doing what it did out of the box. For example the main application class itself can be a security configurer:

.UiApplication.java
[source,java]
----
@SpringBootApplication
@RestController
public class UiApplication extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated().and().httpBasic();
}

...

}
----

=== Loading a Dynamic Resource from Angular

So let's grab that message in the browser. Modify the `AppComponent` to load the protected resource using XHR:
Expand Down Expand Up @@ -255,7 +276,3 @@ On the face of it, it seems like we did a pretty good job, it's concise, easy to
CSRF isn't really an issue with our application as it stands since it only needs to GET the backend resources (i.e. no state is changed in the server). As soon as you have a POST, PUT or DELETE in your application it simply isn't secure any more by any reasonable modern measure.

In the <<_the_login_page_angular_js_and_spring_security_part_ii,next section in this series>> we will extend the application to use form-based authentication, which is a lot more flexible than HTTP Basic. Once we have a form we will need CSRF protection, and both Spring Security and Angular have some nice out-of-the box features to help with this. Spoiler: we are going to need to use the `HttpSession`.

****
Thanks: I would like to thank everyone who helped me develop this series, and in particular http://spring.io/team/rwinch[Rob Winch] and https://twitter.com/thspaeth[Thorsten Spaeth] for their careful reviews of the text and source code, and for teaching me a few tricks I didn't know even about the parts I thought I was most familar with.
****
4 changes: 2 additions & 2 deletions basic/pom.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.test</groupId>
Expand All @@ -14,7 +14,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.10.RELEASE</version>
<version>2.0.3.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>

Expand Down
29 changes: 18 additions & 11 deletions basic/src/main/java/demo/UiApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,30 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class UiApplication {
public class UiApplication extends WebSecurityConfigurerAdapter {

@RequestMapping("/resource")
public Map<String,Object> home() {
Map<String,Object> model = new HashMap<String,Object>();
model.put("id", UUID.randomUUID().toString());
model.put("content", "Hello World");
return model;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated().and().httpBasic();
}

public static void main(String[] args) {
SpringApplication.run(UiApplication.class, args);
}
@RequestMapping("/resource")
public Map<String, Object> home() {
Map<String, Object> model = new HashMap<String, Object>();
model.put("id", UUID.randomUUID().toString());
model.put("content", "Hello World");
return model;
}

public static void main(String[] args) {
SpringApplication.run(UiApplication.class, args);
}

}
7 changes: 4 additions & 3 deletions basic/src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
security:
user:
password: password
spring:
security:
user:
password: password
23 changes: 12 additions & 11 deletions basic/src/test/java/demo/ApplicationTests.java
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
package demo;

import static org.junit.Assert.assertEquals;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.context.embedded.LocalServerPort;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;

import static org.assertj.core.api.Assertions.assertThat;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class ApplicationTests {

@LocalServerPort
private int port;
@Autowired
private TestRestTemplate rest;

@Test
public void homePageProtected() {
ResponseEntity<String> response = new TestRestTemplate().getForEntity("http://localhost:" + port + "/", String.class);
assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode());
}
@Test
public void homePageProtected() {
ResponseEntity<String> response = rest.getForEntity("/", String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
}

}
84 changes: 84 additions & 0 deletions double/.vscode/launch.test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
{
"run": {
"default": "",
"items": [
{
"name": "double-gateway",
"projectName": "double-gateway",
"workingDirectory": "/home/dsyer/dev/guides/tutorials/tut-spring-security-and-angular-js/double",
"args": [],
"vmargs": [],
"env": {},
"preLaunchTask": ""
},
{
"name": "double-ui",
"projectName": "double-ui",
"workingDirectory": "/home/dsyer/dev/guides/tutorials/tut-spring-security-and-angular-js/double",
"args": [],
"vmargs": [],
"env": {},
"preLaunchTask": ""
},
{
"name": "double-resource",
"projectName": "double-resource",
"workingDirectory": "/home/dsyer/dev/guides/tutorials/tut-spring-security-and-angular-js/double",
"args": [],
"vmargs": [],
"env": {},
"preLaunchTask": ""
},
{
"name": "double-admin",
"projectName": "double-admin",
"workingDirectory": "/home/dsyer/dev/guides/tutorials/tut-spring-security-and-angular-js/double",
"args": [],
"vmargs": [],
"env": {},
"preLaunchTask": ""
}
]
},
"debug": {
"default": "",
"items": [
{
"name": "double-gateway",
"projectName": "double-gateway",
"workingDirectory": "/home/dsyer/dev/guides/tutorials/tut-spring-security-and-angular-js/double",
"args": [],
"vmargs": [],
"env": {},
"preLaunchTask": ""
},
{
"name": "double-ui",
"projectName": "double-ui",
"workingDirectory": "/home/dsyer/dev/guides/tutorials/tut-spring-security-and-angular-js/double",
"args": [],
"vmargs": [],
"env": {},
"preLaunchTask": ""
},
{
"name": "double-resource",
"projectName": "double-resource",
"workingDirectory": "/home/dsyer/dev/guides/tutorials/tut-spring-security-and-angular-js/double",
"args": [],
"vmargs": [],
"env": {},
"preLaunchTask": ""
},
{
"name": "double-admin",
"projectName": "double-admin",
"workingDirectory": "/home/dsyer/dev/guides/tutorials/tut-spring-security-and-angular-js/double",
"args": [],
"vmargs": [],
"env": {},
"preLaunchTask": ""
}
]
}
}
8 changes: 4 additions & 4 deletions double/admin/pom.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.test</groupId>
Expand Down Expand Up @@ -105,23 +105,23 @@
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>http://repo.spring.io/libs-snapshot-local</url>
<url>https://repo.spring.io/libs-snapshot-local</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>http://repo.spring.io/libs-milestone-local</url>
<url>https://repo.spring.io/libs-milestone-local</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>http://repo.spring.io/libs-release-local</url>
<url>https://repo.spring.io/libs-release-local</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
Expand Down
8 changes: 4 additions & 4 deletions double/gateway/pom.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.test</groupId>
Expand Down Expand Up @@ -132,23 +132,23 @@
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>http://repo.spring.io/libs-snapshot-local</url>
<url>https://repo.spring.io/libs-snapshot-local</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>http://repo.spring.io/libs-milestone-local</url>
<url>https://repo.spring.io/libs-milestone-local</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>http://repo.spring.io/libs-release-local</url>
<url>https://repo.spring.io/libs-release-local</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
Expand Down
2 changes: 1 addition & 1 deletion double/pom.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<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">
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.demo</groupId>
Expand Down
8 changes: 4 additions & 4 deletions double/resource/pom.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.test</groupId>
Expand Down Expand Up @@ -64,23 +64,23 @@
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>http://repo.spring.io/libs-snapshot-local</url>
<url>https://repo.spring.io/libs-snapshot-local</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>http://repo.spring.io/libs-milestone-local</url>
<url>https://repo.spring.io/libs-milestone-local</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>http://repo.spring.io/libs-release-local</url>
<url>https://repo.spring.io/libs-release-local</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
Expand Down
Loading