Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
J
java-spring-oidc-example
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
demo
java-spring-oidc-example
Commits
6b5e922b
Commit
6b5e922b
authored
Aug 24, 2018
by
William Loosman
Committed by
陈健
Sep 17, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fixed pom dependencies.
Added ID token support. Added ID token validation.
parent
f6a773f6
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
167 additions
and
58 deletions
+167
-58
pom.xml
pom.xml
+16
-2
Application.java
...main/java/com/github/fromi/openidconnect/Application.java
+1
-1
OAuth2Client.java
...com/github/fromi/openidconnect/security/OAuth2Client.java
+7
-9
OpenIDConnectAuthenticationFilter.java
...idconnect/security/OpenIDConnectAuthenticationFilter.java
+90
-5
UserInfo.java
...ava/com/github/fromi/openidconnect/security/UserInfo.java
+53
-41
No files found.
pom.xml
View file @
6b5e922b
...
@@ -12,7 +12,7 @@
...
@@ -12,7 +12,7 @@
<parent>
<parent>
<groupId>
org.springframework.boot
</groupId>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-parent
</artifactId>
<artifactId>
spring-boot-starter-parent
</artifactId>
<version>
1.1.9
.RELEASE
</version>
<version>
2.0.4
.RELEASE
</version>
</parent>
</parent>
<dependencies>
<dependencies>
...
@@ -20,17 +20,30 @@
...
@@ -20,17 +20,30 @@
<groupId>
org.springframework.boot
</groupId>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-web
</artifactId>
<artifactId>
spring-boot-starter-web
</artifactId>
</dependency>
</dependency>
<dependency>
<dependency>
<groupId>
org.springframework.security.oauth
</groupId>
<groupId>
org.springframework.security.oauth
</groupId>
<artifactId>
spring-security-oauth2
</artifactId>
<artifactId>
spring-security-oauth2
</artifactId>
<version>
2.3.3.RELEASE
</version>
<version>
2.3.3.RELEASE
</version>
</dependency>
</dependency>
<dependency>
<groupId>
org.springframework.security
</groupId>
<artifactId>
spring-security-jwt
</artifactId>
<version>
1.0.9.RELEASE
</version>
</dependency>
<dependency>
<groupId>
com.auth0
</groupId>
<artifactId>
jwks-rsa
</artifactId>
<version>
0.3.0
</version>
</dependency>
<dependency>
<dependency>
<groupId>
com.google.guava
</groupId>
<groupId>
com.google.guava
</groupId>
<artifactId>
guava
</artifactId>
<artifactId>
guava
</artifactId>
<version>
18.0
</version>
<version>
18.0
</version>
</dependency>
</dependency>
<dependency>
<dependency>
<groupId>
junit
</groupId>
<groupId>
junit
</groupId>
<artifactId>
junit
</artifactId>
<artifactId>
junit
</artifactId>
...
@@ -47,6 +60,7 @@
...
@@ -47,6 +60,7 @@
<version>
2.4.0
</version>
<version>
2.4.0
</version>
<scope>
test
</scope>
<scope>
test
</scope>
</dependency>
</dependency>
</dependencies>
</dependencies>
<build>
<build>
...
...
src/main/java/com/github/fromi/openidconnect/Application.java
View file @
6b5e922b
...
@@ -3,7 +3,7 @@ package com.github.fromi.openidconnect;
...
@@ -3,7 +3,7 @@ package com.github.fromi.openidconnect;
import
org.springframework.boot.SpringApplication
;
import
org.springframework.boot.SpringApplication
;
import
org.springframework.boot.autoconfigure.EnableAutoConfiguration
;
import
org.springframework.boot.autoconfigure.EnableAutoConfiguration
;
import
org.springframework.boot.builder.SpringApplicationBuilder
;
import
org.springframework.boot.builder.SpringApplicationBuilder
;
import
org.springframework.boot.
context.web
.SpringBootServletInitializer
;
import
org.springframework.boot.
web.servlet.support
.SpringBootServletInitializer
;
import
org.springframework.context.annotation.ComponentScan
;
import
org.springframework.context.annotation.ComponentScan
;
import
org.springframework.context.annotation.ScopedProxyMode
;
import
org.springframework.context.annotation.ScopedProxyMode
;
...
...
src/main/java/com/github/fromi/openidconnect/security/OAuth2Client.java
View file @
6b5e922b
...
@@ -3,7 +3,6 @@ package com.github.fromi.openidconnect.security;
...
@@ -3,7 +3,6 @@ package com.github.fromi.openidconnect.security;
import
static
org
.
springframework
.
security
.
oauth2
.
common
.
AuthenticationScheme
.
header
;
import
static
org
.
springframework
.
security
.
oauth2
.
common
.
AuthenticationScheme
.
header
;
import
javax.annotation.Resource
;
import
javax.annotation.Resource
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Configuration
;
...
@@ -31,14 +30,13 @@ public class OAuth2Client {
...
@@ -31,14 +30,13 @@ public class OAuth2Client {
@Value
(
"${onegini.oauth2.issuer}"
)
@Value
(
"${onegini.oauth2.issuer}"
)
private
String
issuer
;
private
String
issuer
;
public
static
ProviderConfiguration
providerConfiguration
=
null
;
@Bean
@Bean
public
OAuth2ProtectedResourceDetails
googleOAuth2Details
()
{
public
ProviderConfiguration
getProviderConfiguration
(){
return
new
ProviderDiscoveryClient
(
issuer
).
discover
();
}
//Discover endpoints
@Bean
ProviderDiscoveryClient
dc
=
new
ProviderDiscoveryClient
(
issuer
);
public
OAuth2ProtectedResourceDetails
googleOAuth2Details
(
final
ProviderConfiguration
providerConfiguration
)
{
providerConfiguration
=
dc
.
discover
();
//setup OAuth
//setup OAuth
AuthorizationCodeResourceDetails
conf
=
new
AuthorizationCodeResourceDetails
();
AuthorizationCodeResourceDetails
conf
=
new
AuthorizationCodeResourceDetails
();
...
@@ -59,7 +57,7 @@ public class OAuth2Client {
...
@@ -59,7 +57,7 @@ public class OAuth2Client {
@Bean
@Bean
@Scope
(
value
=
"session"
,
proxyMode
=
ScopedProxyMode
.
INTERFACES
)
@Scope
(
value
=
"session"
,
proxyMode
=
ScopedProxyMode
.
INTERFACES
)
public
OAuth2RestOperations
googleOAuth2RestTemplate
()
{
public
OAuth2RestOperations
googleOAuth2RestTemplate
(
final
ProviderConfiguration
providerConfiguration
)
{
return
new
OAuth2RestTemplate
(
googleOAuth2Details
(),
oAuth2ClientContext
);
return
new
OAuth2RestTemplate
(
googleOAuth2Details
(
providerConfiguration
),
oAuth2ClientContext
);
}
}
}
}
src/main/java/com/github/fromi/openidconnect/security/OpenIDConnectAuthenticationFilter.java
View file @
6b5e922b
package
com
.
github
.
fromi
.
openidconnect
.
security
;
package
com
.
github
.
fromi
.
openidconnect
.
security
;
import
static
com
.
github
.
fromi
.
openidconnect
.
security
.
OAuth2Client
.
providerConfiguration
;
import
static
java
.
util
.
Optional
.
empty
;
import
static
java
.
util
.
Optional
.
empty
;
import
static
org
.
springframework
.
security
.
core
.
authority
.
AuthorityUtils
.
NO_AUTHORITIES
;
import
static
org
.
springframework
.
security
.
core
.
authority
.
AuthorityUtils
.
NO_AUTHORITIES
;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.net.MalformedURLException
;
import
java.security.interfaces.RSAPublicKey
;
import
java.util.Date
;
import
java.util.Map
;
import
javax.annotation.Resource
;
import
javax.annotation.Resource
;
import
javax.servlet.ServletException
;
import
javax.servlet.ServletException
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
javax.servlet.http.HttpServletResponse
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.security.authentication.BadCredentialsException
;
import
org.springframework.security.core.Authentication
;
import
org.springframework.security.core.Authentication
;
import
org.springframework.security.core.AuthenticationException
;
import
org.springframework.security.core.AuthenticationException
;
import
org.springframework.security.jwt.Jwt
;
import
org.springframework.security.jwt.JwtHelper
;
import
org.springframework.security.jwt.crypto.sign.RsaVerifier
;
import
org.springframework.security.oauth2.client.OAuth2RestOperations
;
import
org.springframework.security.oauth2.client.OAuth2RestOperations
;
import
org.springframework.security.oauth2.client.discovery.ProviderConfiguration
;
import
org.springframework.security.oauth2.client.http.AccessTokenRequiredException
;
import
org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails
;
import
org.springframework.security.oauth2.common.OAuth2AccessToken
;
import
org.springframework.security.oauth2.common.exceptions.InvalidTokenException
;
import
org.springframework.security.oauth2.common.exceptions.OAuth2Exception
;
import
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter
;
import
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter
;
import
org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken
;
import
org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken
;
import
com.auth0.jwk.InvalidPublicKeyException
;
import
com.auth0.jwk.Jwk
;
import
com.auth0.jwk.JwkException
;
import
com.auth0.jwk.JwkProvider
;
import
com.auth0.jwk.UrlJwkProvider
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
com.sun.jndi.toolkit.url.Uri
;
public
class
OpenIDConnectAuthenticationFilter
extends
AbstractAuthenticationProcessingFilter
{
public
class
OpenIDConnectAuthenticationFilter
extends
AbstractAuthenticationProcessingFilter
{
@Value
(
"${onegini.oauth2.clientId}"
)
private
String
clientId
;
@Value
(
"${onegini.oauth2.clientSecret}"
)
private
String
clientSecret
;
@Value
(
"${onegini.oauth2.issuer}"
)
private
String
issuer
;
@Resource
@Resource
private
OAuth2RestOperations
restTemplate
;
private
OAuth2RestOperations
restTemplate
;
@Resource
private
ProviderConfiguration
providerConfiguration
;
@Resource
private
OAuth2ProtectedResourceDetails
details
;
protected
OpenIDConnectAuthenticationFilter
(
String
defaultFilterProcessesUrl
)
{
protected
OpenIDConnectAuthenticationFilter
(
String
defaultFilterProcessesUrl
)
{
super
(
defaultFilterProcessesUrl
);
super
(
defaultFilterProcessesUrl
);
setAuthenticationManager
(
authentication
->
authentication
);
// AbstractAuthenticationProcessingFilter requires an authentication manager.
setAuthenticationManager
(
authentication
->
authentication
);
// AbstractAuthenticationProcessingFilter requires an authentication manager.
...
@@ -31,8 +67,57 @@ public class OpenIDConnectAuthenticationFilter extends AbstractAuthenticationPro
...
@@ -31,8 +67,57 @@ public class OpenIDConnectAuthenticationFilter extends AbstractAuthenticationPro
@Override
@Override
public
Authentication
attemptAuthentication
(
HttpServletRequest
request
,
HttpServletResponse
response
)
public
Authentication
attemptAuthentication
(
HttpServletRequest
request
,
HttpServletResponse
response
)
throws
AuthenticationException
,
IOException
,
ServletException
{
throws
AuthenticationException
,
IOException
,
ServletException
{
//todo: use id token for user info instead of endpoint
final
ResponseEntity
<
UserInfo
>
userInfoResponseEntity
=
restTemplate
.
getForEntity
(
providerConfiguration
.
getUserInfoEndpoint
().
toString
(),
UserInfo
.
class
);
//Use ID token to retrieve user info -> when we do this we also verify the ID token
return
new
PreAuthenticatedAuthenticationToken
(
userInfoResponseEntity
.
getBody
(),
empty
(),
NO_AUTHORITIES
);
OAuth2AccessToken
accessToken
;
try
{
accessToken
=
restTemplate
.
getAccessToken
();
}
catch
(
OAuth2Exception
e
)
{
throw
new
BadCredentialsException
(
"Could not obtain access token"
,
e
);
}
try
{
String
idToken
=
accessToken
.
getAdditionalInformation
().
get
(
"id_token"
).
toString
();
String
kid
=
JwtHelper
.
headers
(
idToken
).
get
(
"kid"
);
Jwt
tokenDecoded
=
JwtHelper
.
decodeAndVerify
(
idToken
,
verifier
(
kid
));
Map
<
String
,
String
>
authInfo
=
new
ObjectMapper
().
readValue
(
tokenDecoded
.
getClaims
(),
Map
.
class
);
verifyClaims
(
authInfo
);
UserInfo
user
=
new
UserInfo
().
setId
(
authInfo
.
get
(
"sub"
)).
setName
(
authInfo
.
get
(
"sub"
));
return
new
PreAuthenticatedAuthenticationToken
(
user
,
empty
(),
NO_AUTHORITIES
);
}
catch
(
InvalidTokenException
e
)
{
throw
new
BadCredentialsException
(
"Could not obtain user details from token"
,
e
);
}
catch
(
InvalidPublicKeyException
e
){
throw
new
AccessTokenRequiredException
(
e
.
getMessage
(),
details
);
}
catch
(
JwkException
e
){
throw
new
AccessTokenRequiredException
(
e
.
getMessage
(),
details
);
}
}
//Use UserInfo endpoint to retrieve user info
//final ResponseEntity<UserInfo> userInfoResponseEntity = restTemplate.getForEntity(providerConfiguration.getUserInfoEndpoint().toString(), UserInfo.class);
//return new PreAuthenticatedAuthenticationToken(userInfoResponseEntity.getBody(), empty(), NO_AUTHORITIES);
}
private
RsaVerifier
verifier
(
final
String
kid
)
throws
InvalidPublicKeyException
,
JwkException
{
JwkProvider
provider
=
new
UrlJwkProvider
(
providerConfiguration
.
getJwkSetUri
());
Jwk
jwk
=
provider
.
get
(
kid
);
return
new
RsaVerifier
((
RSAPublicKey
)
jwk
.
getPublicKey
());
}
public
void
verifyClaims
(
Map
claims
)
throws
MalformedURLException
{
int
exp
=
(
int
)
claims
.
get
(
"exp"
);
Date
expireDate
=
new
Date
(
exp
*
1000L
);
Date
now
=
new
Date
();
if
(
expireDate
.
before
(
now
)
||
!
new
Uri
(
issuer
).
getHost
().
equals
(
new
Uri
((
String
)
claims
.
get
(
"iss"
)).
getHost
())
||
!
claims
.
get
(
"aud"
).
equals
(
clientId
))
{
throw
new
RuntimeException
(
"Invalid claims"
);
}
}
}
}
src/main/java/com/github/fromi/openidconnect/security/UserInfo.java
View file @
6b5e922b
package
com
.
github
.
fromi
.
openidconnect
.
security
;
package
com
.
github
.
fromi
.
openidconnect
.
security
;
import
com.fasterxml.jackson.annotation.JsonCreator
;
import
com.fasterxml.jackson.annotation.JsonIgnoreProperties
;
import
com.fasterxml.jackson.annotation.JsonProperty
;
@JsonIgnoreProperties
(
ignoreUnknown
=
true
)
public
class
UserInfo
{
public
class
UserInfo
{
private
final
String
id
;
private
String
id
;
private
final
String
name
;
private
String
name
;
// private final String givenName;
private
String
givenName
;
// private final String familyName;
private
String
familyName
;
// private final String locale;
private
String
locale
;
// private final String preferred_username;
private
String
preferred_username
;
@JsonCreator
public
UserInfo
(){
public
UserInfo
(
@JsonProperty
(
"sub"
)
String
id
//,
//@JsonProperty("name") String name,
}
//@JsonProperty("given_name") String givenName,
//@JsonProperty("family_name") String familyName,
public
UserInfo
setId
(
final
String
id
)
{
//@JsonProperty("locale") String locale,
//@JsonProperty("preferred_username") String preferred_username
){
this
.
id
=
id
;
this
.
id
=
id
;
this
.
name
=
id
;
return
this
;
//this.name = name;
}
//this.givenName = givenName;
//this.familyName = familyName;
public
UserInfo
setName
(
final
String
name
)
{
//this.locale = locale;
this
.
name
=
name
;
//this.preferred_username = preferred_username;
return
this
;
}
public
UserInfo
setGivenName
(
final
String
givenName
)
{
this
.
givenName
=
givenName
;
return
this
;
}
public
UserInfo
setFamilyName
(
final
String
familyName
)
{
this
.
familyName
=
familyName
;
return
this
;
}
public
UserInfo
setLocale
(
final
String
locale
)
{
this
.
locale
=
locale
;
return
this
;
}
public
UserInfo
setPreferred_username
(
final
String
preferred_username
)
{
this
.
preferred_username
=
preferred_username
;
return
this
;
}
}
public
String
getId
()
{
public
String
getId
()
{
...
@@ -38,19 +50,19 @@ public class UserInfo {
...
@@ -38,19 +50,19 @@ public class UserInfo {
return
name
;
return
name
;
}
}
//
public String getGivenName() {
public
String
getGivenName
()
{
//
return givenName;
return
givenName
;
//
}
}
//
//
public String getFamilyName() {
public
String
getFamilyName
()
{
//
return familyName;
return
familyName
;
//
}
}
//
//
public String getLocale() {
public
String
getLocale
()
{
//
return locale;
return
locale
;
//
}
}
//
//
public String getPreferred_username() {
public
String
getPreferred_username
()
{
//
return preferred_username;
return
preferred_username
;
//
}
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment