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
Hide 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 @@
<parent>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-parent
</artifactId>
<version>
1.1.9
.RELEASE
</version>
<version>
2.0.4
.RELEASE
</version>
</parent>
<dependencies>
...
...
@@ -20,17 +20,30 @@
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-web
</artifactId>
</dependency>
<dependency>
<groupId>
org.springframework.security.oauth
</groupId>
<artifactId>
spring-security-oauth2
</artifactId>
<version>
2.3.3.RELEASE
</version>
</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>
<groupId>
com.google.guava
</groupId>
<artifactId>
guava
</artifactId>
<version>
18.0
</version>
</dependency>
<dependency>
<groupId>
junit
</groupId>
<artifactId>
junit
</artifactId>
...
...
@@ -47,6 +60,7 @@
<version>
2.4.0
</version>
<scope>
test
</scope>
</dependency>
</dependencies>
<build>
...
...
src/main/java/com/github/fromi/openidconnect/Application.java
View file @
6b5e922b
...
...
@@ -3,7 +3,7 @@ package com.github.fromi.openidconnect;
import
org.springframework.boot.SpringApplication
;
import
org.springframework.boot.autoconfigure.EnableAutoConfiguration
;
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.ScopedProxyMode
;
...
...
src/main/java/com/github/fromi/openidconnect/security/OAuth2Client.java
View file @
6b5e922b
...
...
@@ -3,7 +3,6 @@ package com.github.fromi.openidconnect.security;
import
static
org
.
springframework
.
security
.
oauth2
.
common
.
AuthenticationScheme
.
header
;
import
javax.annotation.Resource
;
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
;
...
...
@@ -31,14 +30,13 @@ public class OAuth2Client {
@Value
(
"${onegini.oauth2.issuer}"
)
private
String
issuer
;
public
static
ProviderConfiguration
providerConfiguration
=
null
;
@Bean
public
OAuth2ProtectedResourceDetails
googleOAuth2Details
()
{
public
ProviderConfiguration
getProviderConfiguration
(){
return
new
ProviderDiscoveryClient
(
issuer
).
discover
();
}
//Discover endpoints
ProviderDiscoveryClient
dc
=
new
ProviderDiscoveryClient
(
issuer
);
providerConfiguration
=
dc
.
discover
();
@Bean
public
OAuth2ProtectedResourceDetails
googleOAuth2Details
(
final
ProviderConfiguration
providerConfiguration
)
{
//setup OAuth
AuthorizationCodeResourceDetails
conf
=
new
AuthorizationCodeResourceDetails
();
...
...
@@ -59,7 +57,7 @@ public class OAuth2Client {
@Bean
@Scope
(
value
=
"session"
,
proxyMode
=
ScopedProxyMode
.
INTERFACES
)
public
OAuth2RestOperations
googleOAuth2RestTemplate
()
{
return
new
OAuth2RestTemplate
(
googleOAuth2Details
(),
oAuth2ClientContext
);
public
OAuth2RestOperations
googleOAuth2RestTemplate
(
final
ProviderConfiguration
providerConfiguration
)
{
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
;
import
static
com
.
github
.
fromi
.
openidconnect
.
security
.
OAuth2Client
.
providerConfiguration
;
import
static
java
.
util
.
Optional
.
empty
;
import
static
org
.
springframework
.
security
.
core
.
authority
.
AuthorityUtils
.
NO_AUTHORITIES
;
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.servlet.ServletException
;
import
javax.servlet.http.HttpServletRequest
;
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.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.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.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
{
@Value
(
"${onegini.oauth2.clientId}"
)
private
String
clientId
;
@Value
(
"${onegini.oauth2.clientSecret}"
)
private
String
clientSecret
;
@Value
(
"${onegini.oauth2.issuer}"
)
private
String
issuer
;
@Resource
private
OAuth2RestOperations
restTemplate
;
@Resource
private
ProviderConfiguration
providerConfiguration
;
@Resource
private
OAuth2ProtectedResourceDetails
details
;
protected
OpenIDConnectAuthenticationFilter
(
String
defaultFilterProcessesUrl
)
{
super
(
defaultFilterProcessesUrl
);
setAuthenticationManager
(
authentication
->
authentication
);
// AbstractAuthenticationProcessingFilter requires an authentication manager.
...
...
@@ -31,8 +67,57 @@ public class OpenIDConnectAuthenticationFilter extends AbstractAuthenticationPro
@Override
public
Authentication
attemptAuthentication
(
HttpServletRequest
request
,
HttpServletResponse
response
)
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
);
return
new
PreAuthenticatedAuthenticationToken
(
userInfoResponseEntity
.
getBody
(),
empty
(),
NO_AUTHORITIES
);
//Use ID token to retrieve user info -> when we do this we also verify the ID token
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
;
import
com.fasterxml.jackson.annotation.JsonCreator
;
import
com.fasterxml.jackson.annotation.JsonIgnoreProperties
;
import
com.fasterxml.jackson.annotation.JsonProperty
;
@JsonIgnoreProperties
(
ignoreUnknown
=
true
)
public
class
UserInfo
{
private
final
String
id
;
private
final
String
name
;
// private final String givenName;
// private final String familyName;
// private final String locale;
// private final String preferred_username;
@JsonCreator
public
UserInfo
(
@JsonProperty
(
"sub"
)
String
id
//,
//@JsonProperty("name") String name,
//@JsonProperty("given_name") String givenName,
//@JsonProperty("family_name") String familyName,
//@JsonProperty("locale") String locale,
//@JsonProperty("preferred_username") String preferred_username
){
private
String
id
;
private
String
name
;
private
String
givenName
;
private
String
familyName
;
private
String
locale
;
private
String
preferred_username
;
public
UserInfo
(){
}
public
UserInfo
setId
(
final
String
id
)
{
this
.
id
=
id
;
this
.
name
=
id
;
//this.name = name;
//this.givenName = givenName;
//this.familyName = familyName;
//this.locale = locale;
//this.preferred_username = preferred_username;
return
this
;
}
public
UserInfo
setName
(
final
String
name
)
{
this
.
name
=
name
;
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
()
{
...
...
@@ -38,19 +50,19 @@ public class UserInfo {
return
name
;
}
//
public String getGivenName() {
//
return givenName;
//
}
//
//
public String getFamilyName() {
//
return familyName;
//
}
//
//
public String getLocale() {
//
return locale;
//
}
//
//
public String getPreferred_username() {
//
return preferred_username;
//
}
public
String
getGivenName
()
{
return
givenName
;
}
public
String
getFamilyName
()
{
return
familyName
;
}
public
String
getLocale
()
{
return
locale
;
}
public
String
getPreferred_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