Skip to content

Commit 9a95703

Browse files
committed
One Line Per Sentence
Fixes spring-guidesgh-109
1 parent cbaf03b commit 9a95703

File tree

8 files changed

+220
-491
lines changed

8 files changed

+220
-491
lines changed

README.adoc

Lines changed: 14 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,14 @@ projects: [spring-security,spring-security-oauth,spring-boot]
1212

1313
= Social Login with Spring Boot and OAuth2
1414

15-
This guide shows you how to build a sample app doing various things
16-
with "social login" using https://tools.ietf.org/html/rfc6749[OAuth2]
17-
and https://projects.spring.io/spring-boot/[Spring Boot]. It starts
18-
with a simple, single-provider single-sign on, and works up to a
19-
self-hosted OAuth2 Authorization Server with a choice of
20-
authentication providers (https://developers.facebook.com[Facebook] or
21-
https://developer.github.com/[Github]). The samples are all
22-
single-page apps using Spring Boot and Spring OAuth on the back
23-
end. They also all use plain https://jquery.org/[jQuery] on the front
24-
end, but the changes needed to convert to a different JavaScript
25-
framework or to use server side rendering would be minimal.
26-
27-
Because one of the samples is a full OAuth2 Authorization Server we
28-
have used the
29-
https://docs.spring.io/spring-security-oauth2-boot/docs/current/reference/htmlsingle/[shim
30-
JAR] which supports bridging from Spring Boot 2.0 to the old Spring
31-
Security OAuth2 library. The simpler samples could also be implemented
32-
using the native OAuth2 support in
33-
https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-security-oauth2[Spring
34-
Boot] security features. The configuration is very similar.
15+
This guide shows you how to build a sample app doing various things with "social login" using https://tools.ietf.org/html/rfc6749[OAuth2] and https://projects.spring.io/spring-boot/[Spring Boot].
16+
It starts with a simple, single-provider single-sign on, and works up to a self-hosted OAuth2 Authorization Server with a choice of authentication providers (https://developers.facebook.com[Facebook] or https://developer.github.com/[Github]).
17+
The samples are all single-page apps using Spring Boot and Spring OAuth on the back end.
18+
They also all use plain https://jquery.org/[jQuery] on the front end, but the changes needed to convert to a different JavaScript framework or to use server side rendering would be minimal.
19+
20+
Because one of the samples is a full OAuth2 Authorization Server we have used the https://docs.spring.io/spring-security-oauth2-boot/docs/current/reference/htmlsingle/[shim JAR] which supports bridging from Spring Boot 2.0 to the old Spring Security OAuth2 library.
21+
The simpler samples could also be implemented using the native OAuth2 support in https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-security-oauth2[Spring Boot] security features.
22+
The configuration is very similar.
3523

3624
include::overview.adoc[]
3725

@@ -45,17 +33,11 @@ include::custom-error/README.adoc[leveloffset=+1]
4533

4634
== Conclusion
4735

48-
We have seen how to use Spring Boot and Spring Security to build apps
49-
in a number of styles with very little effort. The main theme running
50-
through all of the samples is "social" login using an external OAuth2
51-
provider. The final sample could even be used to provide such a
52-
service "internally" because it has the same basic features that the
53-
external providers have. All of the sample apps can be easily extended
54-
and re-configured for more specific use cases, usually with nothing
55-
more than a configuration file change. Remember if you use versions of
56-
the samples in your own servers to register with Facebook or Github
57-
(or similar) and get client credentials for your own host
58-
addresses. And remember not to put those credentials in source
59-
control!
36+
We have seen how to use Spring Boot and Spring Security to build apps in a number of styles with very little effort.
37+
The main theme running through all of the samples is "social" login using an external OAuth2 provider.
38+
The final sample could even be used to provide such a service "internally" because it has the same basic features that the external providers have.
39+
All of the sample apps can be easily extended and re-configured for more specific use cases, usually with nothing more than a configuration file change.
40+
Remember if you use versions of the samples in your own servers to register with Facebook or Github (or similar) and get client credentials for your own host addresses.
41+
And remember not to put those credentials in source control!
6042

6143
include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/master/footer.adoc[]

auth-server/README.adoc

Lines changed: 55 additions & 123 deletions
Large diffs are not rendered by default.

click/README.adoc

Lines changed: 24 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,14 @@
11
[[_social_login_click]]
22
= Add a Welcome Page
33

4-
In this section we modify the <<_social_login_simple,simple>> app we
5-
just built, by adding an explicit link to login with Facebook. Instead
6-
of being redirected immediately, the new link will be visible on the
7-
home page, and the user can choose to login or to stay
8-
unauthenticated. Only when the user has clicked on the link will he be
9-
shown the secure content.
4+
In this section we modify the <<_social_login_simple,simple>> app we just built, by adding an explicit link to login with Facebook.
5+
Instead of being redirected immediately, the new link will be visible on the home page, and the user can choose to login or to stay unauthenticated.
6+
Only when the user has clicked on the link will he be shown the secure content.
107

118
== Conditional Content in Home Page
129

13-
To render some content conditional on whether the user is
14-
authenticated or not we could use server side rendering (e.g. with
15-
Freemarker or Tymeleaf), or we can just ask the browser to to it,
16-
using some JavaScript. To do that we are going to use
17-
https://angularjs.org/[AngularJS], but if you prefer to use a
18-
different framework, it shouldn't be very hard to translate the client
19-
code.
10+
To render some content conditional on whether the user is authenticated or not we could use server side rendering (e.g. with Freemarker or Tymeleaf), or we can just ask the browser to to it, using some JavaScript.
11+
To do that we are going to use https://angularjs.org/[AngularJS], but if you prefer to use a different framework, it shouldn't be very hard to translate the client code.
2012

2113
To get started with the dynamic content we need to mark up the HTML in parts of it are going to display it:
2214

@@ -31,10 +23,8 @@ To get started with the dynamic content we need to mark up the HTML in parts of
3123
</div>
3224
----
3325

34-
This HTML sets us up with a need for some client side code that manipulates the
35-
`authenticated`, `unauthenticated` and `user` elements.
36-
Here's a simple implementation of those features (drop them in
37-
at the end of the `<body>`):
26+
This HTML sets us up with a need for some client side code that manipulates the `authenticated`, `unauthenticated` and `user` elements.
27+
Here's a simple implementation of those features (drop them in at the end of the `<body>`):
3828

3929
.index.html
4030
[source,html]
@@ -50,9 +40,9 @@ at the end of the `<body>`):
5040

5141
== Server Side Changes
5242

53-
For this to work we need some changes on the server side. The "home"
54-
controller needs an endpoint at "/user" that describes the currently
55-
authenticated user. That's quite easy to do, e.g. in our main class:
43+
For this to work we need some changes on the server side.
44+
The "home" controller needs an endpoint at "/user" that describes the currently authenticated user.
45+
That's quite easy to do, e.g. in our main class:
5646

5747
.SocialApplication
5848
[source,java]
@@ -74,19 +64,14 @@ public class SocialApplication {
7464
}
7565
----
7666

77-
Note the use of `@RestController` and `@RequestMapping` and the
78-
`java.security.Principal` we inject into the handler method.
67+
Note the use of `@RestController` and `@RequestMapping` and the `java.security.Principal` we inject into the handler method.
7968

80-
WARNING: It's not a great idea to return a whole `Principal` in a
81-
`/user` endpoint like that (it might contain information you would
82-
rather not reveal to a browser client). We only did it to get
83-
something working quickly. Later in the guide we will convert the
84-
endpoint to hide the information we don't need the browser to have.
69+
WARNING: It's not a great idea to return a whole `Principal` in a `/user` endpoint like that (it might contain information you would rather not reveal to a browser client).
70+
We only did it to get something working quickly.
71+
Later in the guide we will convert the endpoint to hide the information we don't need the browser to have.
8572

86-
This app will now work fine and authenticate as before, but without
87-
giving the user a chance to click on the link we just provided. To
88-
make the link visible we also need to switch off the security on the
89-
home page by adding a `WebSecurityConfigurer`:
73+
This app will now work fine and authenticate as before, but without giving the user a chance to click on the link we just provided.
74+
To make the link visible we also need to switch off the security on the home page by adding a `WebSecurityConfigurer`:
9075

9176
.SocialApplication
9277
[source,java]
@@ -112,25 +97,12 @@ public class SocialApplication extends WebSecurityConfigurerAdapter {
11297
}
11398
----
11499

115-
Spring Boot attaches a special meaning to a `WebSecurityConfigurer` on
116-
the class that carries the `@EnableOAuth2Sso` annotation: it uses it
117-
to configure the security filter chain that carries the OAuth2
118-
authentication processor. So all we need to do to make our home page
119-
visible is to explicitly `authorizeRequests()` to the home page and
120-
the static resources it contains (we also include access to the login
121-
endpoints which handle the authentication). All other requests
122-
(e.g. to the `/user` endpoint) require authentication.
123-
124-
NOTE: `/error**` is an unprotected path because we want Spring Boot
125-
to be able to render errors if there is a problem in the app, even
126-
if the user is unauthenticated.
127-
128-
With that change in place the application is complete, and if you run
129-
it and visit the home page you should see a nicely styled HTML link to
130-
"login with Facebook". The link takes you not directly to Facebook,
131-
but to the local path that processes the authentication (and sends a
132-
redirect to Facebook). Once you have authenticated you get redirected
133-
back to the local app, where it now displays your name (assuming you
134-
have set up your permissions in Facebook to allow access to that
135-
data).
100+
Spring Boot attaches a special meaning to a `WebSecurityConfigurer` on the class that carries the `@EnableOAuth2Sso` annotation: it uses it to configure the security filter chain that carries the OAuth2 authentication processor.
101+
So all we need to do to make our home page visible is to explicitly `authorizeRequests()` to the home page and the static resources it contains (we also include access to the login endpoints which handle the authentication).
102+
All other requests (e.g. to the `/user` endpoint) require authentication.
136103

104+
NOTE: `/error**` is an unprotected path because we want Spring Boot to be able to render errors if there is a problem in the app, even if the user is unauthenticated.
105+
106+
With that change in place the application is complete, and if you run it and visit the home page you should see a nicely styled HTML link to "login with Facebook".
107+
The link takes you not directly to Facebook, but to the local path that processes the authentication (and sends a redirect to Facebook).
108+
Once you have authenticated you get redirected back to the local app, where it now displays your name (assuming you have set up your permissions in Facebook to allow access to that data).

custom-error/README.adoc

Lines changed: 27 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,14 @@
11
[[_custom_error]]
22
= Adding an Error Page for Unauthenticated Users
33

4-
In this section we modify the <<_social_login_logout,logout>> app we
5-
built earlier, switching to Github authentication, and also giving
6-
some feedback to users that cannot authenticate. At the same time we
7-
take the opportunity to extend the authentication logic to include a
8-
rule that only allows users if they belong to a specific Github
9-
organization. The "organization" is a Github domain-specific concept,
10-
but similar rules could be devised for other providers, e.g. with
11-
Google you might want to only authenticate users from a specific
12-
domain.
4+
In this section we modify the <<_social_login_logout,logout>> app we built earlier, switching to Github authentication, and also giving some feedback to users that cannot authenticate.
5+
At the same time we take the opportunity to extend the authentication logic to include a rule that only allows users if they belong to a specific Github organization.
6+
The "organization" is a Github domain-specific concept, but similar rules could be devised for other providers, e.g. with Google you might want to only authenticate users from a specific domain.
137

148
== Switching to Github
159

16-
The <<_social_login_logout,logout>> sample use Facebook as an OAuth2
17-
provider. We can easily switch to Github by changing the local
18-
configuration:
10+
The <<_social_login_logout,logout>> sample use Facebook as an OAuth2 provider.
11+
We can easily switch to Github by changing the local configuration:
1912

2013
.application.yml
2114
[source,yaml]
@@ -34,9 +27,8 @@ security:
3427

3528
== Detecting an Authentication Failure in the Client
3629

37-
On the client we need to be able to provide some feedback for a user
38-
that could not authenticate. To facilitate this we add a div with an
39-
informative message:
30+
On the client we need to be able to provide some feedback for a user that could not authenticate.
31+
To facilitate this we add a div with an informative message:
4032

4133
.index.html
4234
----
@@ -45,8 +37,7 @@ There was an error (bad credentials).
4537
</div>
4638
----
4739

48-
This text will only be shown when the "error" element is shown,
49-
so we need some code to do that:
40+
This text will only be shown when the "error" element is shown, so we need some code to do that:
5041

5142
.index.html
5243
----
@@ -68,15 +59,12 @@ $.ajax({
6859
});
6960
----
7061

71-
The authentication function checks the browser location when it loads
72-
and if it finds a URL with "error=true" in it, the flag is set.
62+
The authentication function checks the browser location when it loads and if it finds a URL with "error=true" in it, the flag is set.
7363

7464
== Adding an Error Page
7565

76-
To support the flag setting in the client we need to be able to
77-
capture an authentication error and redirect to the home page
78-
with that flag set in query parameters. Hence we need an
79-
endpoint, in a regular `@Controller` like this:
66+
To support the flag setting in the client we need to be able to capture an authentication error and redirect to the home page with that flag set in query parameters.
67+
Hence we need an endpoint, in a regular `@Controller` like this:
8068

8169
.SocialApplication.java
8270
[source,java]
@@ -87,11 +75,8 @@ public String unauthenticated() {
8775
}
8876
----
8977

90-
In the sample app we put this in the main application class, which is
91-
now a `@Controller` (not a `@RestController`) so it can handle the
92-
redirect. The last thing we need is a mapping from an unauthenticated
93-
response (HTTP 401, a.k.a. UNAUTHORIZED) to the "/unauthenticated"
94-
endpoint we just added:
78+
In the sample app we put this in the main application class, which is now a `@Controller` (not a `@RestController`) so it can handle the redirect.
79+
The last thing we need is a mapping from an unauthenticated response (HTTP 401, a.k.a. UNAUTHORIZED) to the "/unauthenticated" endpoint we just added:
9580

9681
.ServletCustomizer.java
9782
[source,java]
@@ -107,26 +92,16 @@ public class ServletCustomizer {
10792
}
10893
----
10994

110-
(In the sample, this is added as a nested class inside the main
111-
application, just for conciseness.)
95+
(In the sample, this is added as a nested class inside the main application, just for conciseness.)
11296

11397
== Generating a 401 in the Server
11498

115-
A 401 response will already be coming from Spring Security if the user
116-
cannot or does not want to login with Github, so the app is already
117-
working if you fail to authenticate (e.g. by rejecting the token
118-
grant).
119-
120-
To spice things up a bit we will extend the authentication rule to
121-
reject users that are not in the right organization. It is easy to use
122-
the Github API to find out more about the user, so we just need to
123-
plug that into the right part of the authentication
124-
process. Fortunately, for such a simple use case, Spring Boot has
125-
provided an easy extension point: if we declare a `@Bean` of type
126-
`AuthoritiesExtractor` it will be used to construct the authorities
127-
(typically "roles") of an authenticated user. We can use that hook to
128-
assert the the user is in the correct orignization, and throw an
129-
exception if not:
99+
A 401 response will already be coming from Spring Security if the user cannot or does not want to login with Github, so the app is already working if you fail to authenticate (e.g. by rejecting the token grant).
100+
101+
To spice things up a bit we will extend the authentication rule to reject users that are not in the right organization.
102+
It is easy to use the Github API to find out more about the user, so we just need to plug that into the right part of the authentication process.
103+
Fortunately, for such a simple use case, Spring Boot has provided an easy extension point: if we declare a `@Bean` of type `AuthoritiesExtractor` it will be used to construct the authorities (typically "roles") of an authenticated user.
104+
We can use that hook to assert the the user is in the correct organization, and throw an exception if not:
130105

131106
.SocialApplication.java
132107
[source,java]
@@ -146,19 +121,12 @@ public AuthoritiesExtractor authoritiesExtractor(OAuth2RestOperations template)
146121
}
147122
----
148123

149-
Note that we have autowired a `OAuth2RestOperations` into this method,
150-
so we can use that to access the Github API on behalf of the
151-
authenticated user. We do that, and loop over the organizations,
152-
looking for one that matches "spring-projects" (this is the
153-
organization that is used to store Spring open source projects). You
154-
can substitute your own value there if you want to be able to
155-
authenticate successfully and you are not in the Spring Engineering
156-
team. If there is no match, we throw `BadCredentialsException` and
157-
this is picked up by Spring Security and turned in to a 401 response.
124+
Note that we have autowired a `OAuth2RestOperations` into this method, so we can use that to access the Github API on behalf of the authenticated user.
125+
We do that, and loop over the organizations, looking for one that matches "spring-projects" (this is the organization that is used to store Spring open source projects).
126+
You can substitute your own value there if you want to be able to authenticate successfully and you are not in the Spring Engineering team.
127+
If there is no match, we throw `BadCredentialsException` and this is picked up by Spring Security and turned in to a 401 response.
158128

159-
The `OAuth2RestOperations` has to be created as a bean as well (as of
160-
Spring Boot 1.4), but that's trivial because its ingredients are all
161-
autowirable by virtue of having used `@EnableOAuth2Sso`:
129+
The `OAuth2RestOperations` has to be created as a bean as well (as of Spring Boot 1.4), but that's trivial because its ingredients are all autowirable by virtue of having used `@EnableOAuth2Sso`:
162130

163131
[source,java,indent=0]
164132
----
@@ -168,7 +136,5 @@ public OAuth2RestTemplate oauth2RestTemplate(OAuth2ProtectedResourceDetails reso
168136
}
169137
----
170138

171-
TIP: Obviously the code above can be generalized to other
172-
authentication rules, some applicable to Github and some to other
173-
OAuth2 providers. All you need is the `OAuth2RestOperations` and some
174-
knowledge of the provider's API.
139+
TIP: Obviously the code above can be generalized to other authentication rules, some applicable to Github and some to other OAuth2 providers.
140+
All you need is the `OAuth2RestOperations` and some knowledge of the provider's API.

0 commit comments

Comments
 (0)