UAA server - org.springframework.security.authentication.BadCredentialsException: Bad credentials - spring

The client needs to get a token from UAA server, but when the request was sent, I alway got the error as follows:
org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent[source=org.springframework.security.authentication.UsernamePasswordAuthenticationToken#48d8d90a: Principal: admin-portal-ui; Credentials: [PROTECTED]; Authenticated: false; Details: remoteAddress=127.0.0.1, clientId=admin-portal-ui; Not granted any authorities]
The UAA server log are shown below:
[2016-11-21 18:40:57.008] cloudfoundry-identity-server - ???? [http-apr-8080-exec-2] .... DEBUG --- UaaRequestMatcher: [loginAuthorizeRequestMatcherOld] Checking match of request : '/uaa/oauth/token'; '/uaa/oauth/authorize' with parameters={login={} and headers {accept=[application/json]}
[2016-11-21 18:40:57.008] cloudfoundry-identity-server - ???? [http-apr-8080-exec-2] .... DEBUG --- UaaRequestMatcher: [passcodeTokenMatcher] Checking match of request : '/uaa/oauth/token'; '/uaa/oauth/token' with parameters={grant_type=password, passcode=} and headers {accept=[application/json, application/x-www-form-urlencoded]}
[2016-11-21 18:40:57.008] cloudfoundry-identity-server - ???? [http-apr-8080-exec-2] .... DEBUG --- CorsFilter: CORS Processing request: URI: /uaa/oauth/token; Scheme: http; Host: localhost; Port: 8080; Origin: http://localhost:81; Method: POST
[2016-11-21 18:40:57.008] cloudfoundry-identity-server - ???? [http-apr-8080-exec-2] .... DEBUG --- CorsFilter: Request cross origin request has passed validation.
[2016-11-21 18:40:57.012] cloudfoundry-identity-server - ???? [http-apr-8080-exec-2] .... DEBUG --- DisableIdTokenResponseTypeFilter: Processing id_token disable filter
[2016-11-21 18:40:57.012] cloudfoundry-identity-server - ???? [http-apr-8080-exec-2] .... DEBUG --- DisableIdTokenResponseTypeFilter: pre id_token disable:false pathinfo:null request_uri:/uaa/oauth/token response_type:token
[2016-11-21 18:40:57.012] cloudfoundry-identity-server - ???? [http-apr-8080-exec-2] .... DEBUG --- DisableIdTokenResponseTypeFilter: post id_token disable:false pathinfo:null request_uri:/uaa/oauth/token response_type:token
[2016-11-21 18:40:57.012] cloudfoundry-identity-server - ???? [http-apr-8080-exec-2] .... DEBUG --- SecurityFilterChainPostProcessor$HttpsEnforcementFilter: Filter chain 'tokenEndpointSecurity' processing request POST /uaa/oauth/token
[2016-11-21 18:40:57.095] cloudfoundry-identity-server - ???? [http-apr-8080-exec-2] .... INFO --- Audit: PrincipalAuthenticationFailure ('null'): principal=admin-portal-ui, origin=[127.0.0.1], identityZoneId=[uaa]
[2016-11-21 18:40:57.095] cloudfoundry-identity-server - ???? [http-apr-8080-exec-2] .... INFO --- Audit: ClientAuthenticationFailure ('Bad credentials'): principal=admin-portal-ui, origin=[remoteAddress=127.0.0.1, clientId=admin-portal-ui], identityZoneId=[uaa]
[2016-11-21 18:40:57.095] cloudfoundry-identity-server - ???? [http-apr-8080-exec-2] .... DEBUG --- CorsFilter: CORS processing completed for: URI: /uaa/oauth/token; Scheme: http; Host: localhost; Port: 8080; Origin: http://localhost:81; Method: POST Status:401
Below is the login-server-security.xml :
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security" xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<oauth:resource-server id="oauthResourceAuthenticationFilter" token-services-ref="tokenServices"
resource-id="oauth" entry-point-ref="oauthAuthenticationEntryPoint" />
<http name="secFilterLoginServerAuthenticate" request-matcher-ref="loginAuthenticateRequestMatcher" create-session="never" entry-point-ref="oauthAuthenticationEntryPoint"
authentication-manager-ref="loginAuthenticationMgr" xmlns="http://www.springframework.org/schema/security" use-expressions="false">
<intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
<custom-filter ref="oauthResourceAuthenticationFilter" position="PRE_AUTH_FILTER" />
<!-- scope authentication filter configured with a scope authentication manager -->
<custom-filter ref="oauthLoginScopeAuthenticatingFilter" after="PRE_AUTH_FILTER"/>
<anonymous enabled="false" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
<csrf disabled="true"/>
</http>
<bean id="loginAuthenticateRequestMatcher" class="org.cloudfoundry.identity.uaa.security.web.UaaRequestMatcher">
<constructor-arg value="/authenticate" />
<property name="accept" value="application/json" />
<property name="headers">
<map>
<entry key="Authorization" value="bearer " />
</map>
</property>
</bean>
<sec:http name="secFilterAuthenticateOpen" pattern="/authenticate/**" security="none" />
<http name="secFilterLoginServerAuthorize" request-matcher-ref="loginAuthorizeRequestMatcher" create-session="never" entry-point-ref="oauthAuthenticationEntryPoint"
authentication-manager-ref="loginAuthenticationMgr" xmlns="http://www.springframework.org/schema/security" use-expressions="false">
<intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
<custom-filter ref="backwardsCompatibleScopeParameter" position="FIRST"/>
<custom-filter ref="oauthResourceAuthenticationFilter" position="PRE_AUTH_FILTER" />
<!-- scope authentication filter configured with a scope authentication manager -->
<custom-filter ref="oauthLoginScopeAuthenticatingFilter" after="PRE_AUTH_FILTER"/>
<custom-filter ref="loginAuthenticationFilter" position="FORM_LOGIN_FILTER" />
<anonymous enabled="false" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
<csrf disabled="true"/>
</http>
<bean id="loginAuthorizeRequestMatcher" class="org.cloudfoundry.identity.uaa.security.web.UaaRequestMatcher">
<constructor-arg value="/oauth/authorize" />
<property name="accept" value="application/json" />
<property name="parameters">
<map>
<entry key="source" value="login" />
</map>
</property>
</bean>
<http name="secFilterLoginServerToken" request-matcher-ref="loginTokenRequestMatcher" create-session="never" entry-point-ref="oauthAuthenticationEntryPoint"
authentication-manager-ref="loginAuthenticationMgr" xmlns="http://www.springframework.org/schema/security" use-expressions="false">
<!--
This represents a /oauth/token requests that gets passed through
from the login server. It assumes that the User has been authenticated
It requires that:
- userid parameter exists
- client_id and client_secret are present
- Bearer token belongs to login server (oauth.login) validated as resource="oauth"
-->
<intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
<!-- the oauthResourceAuthenticationFilter validates the Bearer token
TODO, if there is no token this filter must throw.
What we need is scope=oauth.login
-->
<custom-filter ref="backwardsCompatibleScopeParameter" position="FIRST"/>
<custom-filter ref="oauthResourceAuthenticationFilter" position="PRE_AUTH_FILTER" />
<!-- scope authentication filter configured with a scope authentication manager -->
<custom-filter ref="oauthLoginScopeAuthenticatingFilter" after="PRE_AUTH_FILTER"/>
<!-- filter to validate the client_id and client_secret -->
<custom-filter ref="loginClientParameterAuthenticationFilter" position="FORM_LOGIN_FILTER" />
<!-- The loginServerTokenEndpointAuthenticationFilter validates the user or creates one-->
<custom-filter ref="loginServerTokenEndpointAuthenticationFilter" position="BASIC_AUTH_FILTER"/>
<anonymous enabled="false" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
<csrf disabled="true"/>
</http>
<bean id="oauthLoginScopeAuthenticatingFilter" class="org.cloudfoundry.identity.uaa.authentication.manager.ScopeAuthenticationFilter">
<property name="authenticationManager" ref="oauthLoginAuthManager"/>
</bean>
<bean id="oauthLoginAuthManager" class="org.cloudfoundry.identity.uaa.authentication.manager.ScopeAuthenticationManager">
<property name="requiredScopes">
<list>
<value type="java.lang.String">oauth.login</value>
</list>
</property>
</bean>
<bean id="loginTokenRequestMatcher" class="org.cloudfoundry.identity.uaa.security.web.UaaRequestMatcher">
<constructor-arg value="/oauth/token" />
<property name="accept" value="application/json" />
<property name="headers">
<map>
<entry key="Authorization" value="bearer " />
</map>
</property>
<property name="parameters">
<map>
<entry key="source" value="login" />
<entry key="grant_type" value="password" />
<entry key="add_new" value="" />
</map>
</property>
</bean>
<bean id="loginServerTokenEndpointAuthenticationFilter" class="org.cloudfoundry.identity.uaa.authentication.LoginServerTokenEndpointFilter">
<constructor-arg ref="loginAuthenticationMgr" />
<constructor-arg ref="authorizationRequestManager"/>
<constructor-arg ref="addNewUserParameters"/>
<property name="authenticationDetailsSource" ref="authenticationDetailsSource" />
</bean>
<bean id="loginClientParameterAuthenticationFilter" class="org.cloudfoundry.identity.uaa.authentication.LoginClientParametersAuthenticationFilter">
<property name="clientAuthenticationManager" ref="clientAuthenticationManager"/>
</bean>
<!-- Support for older login servers -->
<http name="secFilterLoginServerAuthorizeOld" request-matcher-ref="loginAuthorizeRequestMatcherOld" create-session="always" entry-point-ref="oauthAuthenticationEntryPoint"
authentication-manager-ref="loginAuthenticationMgr" xmlns="http://www.springframework.org/schema/security" use-expressions="false">
<intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
<custom-filter ref="backwardsCompatibleScopeParameter" position="FIRST"/>
<custom-filter ref="oauthResourceAuthenticationFilter" position="PRE_AUTH_FILTER" />
<custom-filter ref="loginAuthenticationFilter" position="FORM_LOGIN_FILTER" />
<anonymous enabled="false" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
<csrf disabled="true"/>
</http>
<bean id="loginAuthorizeRequestMatcherOld" class="org.cloudfoundry.identity.uaa.security.web.UaaRequestMatcher">
<constructor-arg value="/oauth/authorize" />
<property name="accept" value="application/json" />
<property name="parameters">
<map>
<entry key="login" value="{" />
</map>
</property>
</bean>
<!-- End support for older login servers -->
<util:list id="addNewUserParameters" value-type="java.lang.String">
<value>login</value>
<value>username</value>
<value>user_id</value>
<value>origin</value>
<value>given_name</value>
<value>family_name</value>
<value>email</value>
<value>authorities</value>
</util:list>
<bean id="loginAuthenticationFilter" class="org.cloudfoundry.identity.uaa.authentication.AuthzAuthenticationFilter">
<constructor-arg ref="loginAuthenticationMgr" />
<property name="parameterNames" ref="addNewUserParameters"/>
</bean>
<bean id="loginAuthenticationMgr" class="org.cloudfoundry.identity.uaa.authentication.manager.LoginAuthenticationManager">
<property name="userDatabase" ref="userDatabase" />
</bean>
<bean class="org.cloudfoundry.identity.uaa.authentication.RemoteAuthenticationEndpoint">
<constructor-arg ref="zoneAwareAuthzAuthenticationManager" />
<property name="loginAuthenticationManager" ref="loginAuthenticationMgr"/>
</bean>
<bean id="codeStore" class="org.cloudfoundry.identity.uaa.codestore.JdbcExpiringCodeStore">
<constructor-arg ref="dataSource" />
</bean>
<bean id="passwordResetEndpoints" class="org.cloudfoundry.identity.uaa.account.PasswordResetEndpoint">
<constructor-arg ref="resetPasswordService"/>
<property name="messageConverters">
<list>
<bean class="org.cloudfoundry.identity.uaa.web.ExceptionReportHttpMessageConverter" />
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
</list>
</property>
<property name="codeStore" ref="codeStore"/>
</bean>
<bean id="changeEmailEndpoints" class="org.cloudfoundry.identity.uaa.scim.endpoints.ChangeEmailEndpoints">
<constructor-arg ref="scimUserProvisioning"/>
<constructor-arg ref="codeStore"/>
<constructor-arg ref="clientDetailsService"/>
</bean>
<http name="secFilterLoginServerPasswordEndpoints" create-session="stateless" entry-point-ref="oauthAuthenticationEntryPoint" authentication-manager-ref="emptyAuthenticationManager"
access-decision-manager-ref="accessDecisionManager" pattern="/password_*" xmlns="http://www.springframework.org/schema/security" use-expressions="false">
<intercept-url pattern="/**" access="scope=oauth.login" />
<custom-filter ref="oauthResourceAuthenticationFilter" position="PRE_AUTH_FILTER" />
<anonymous enabled="false" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
<csrf disabled="true"/>
</http>
<http name="secFilterLoginServerEmailEndpoints" create-session="stateless" entry-point-ref="oauthAuthenticationEntryPoint" authentication-manager-ref="emptyAuthenticationManager"
access-decision-manager-ref="accessDecisionManager" pattern="/email_*" xmlns="http://www.springframework.org/schema/security" use-expressions="false">
<intercept-url pattern="/**" access="scope=oauth.login" />
<custom-filter ref="oauthResourceAuthenticationFilter" position="PRE_AUTH_FILTER" />
<anonymous enabled="false" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
<csrf disabled="true"/>
</http>
</beans>
And there is a configuration uaa.yml as follows:
login:
#Disable create account and forgot password links on the Login Server
selfServiceLinksEnabled: false
# Configure branding for the UAA
branding:
companyName: Consent2Share
productLogo: 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
#Configure to enable to limit login failure attempts
authentication:
policy:
lockoutAfterFailures: 5
countFailuresWithinSeconds: 3600
lockoutPeriodSeconds: 600
# Patient User will use the e-mail server configured in this section to send e-mails
# Please configure valid e-mail server below to connect to SMTP server
# Configure host, port, username and password per environment
smtp:
host: ${UAA_SMTP_HOST}
port: ${UAA_SMTP_PORT}
user: ${UAA_SMTP_USER}
password: ${UAA_SMTP_PASSWORD}
javaMailProperties:
mail:
smtp:
auth: true
starttls:
enable: true
ssl:
trust: ${UAA_SMTP_HOST}
debug: true
spring_profiles: mysql # default is empty
database:
driverClassName: org.mariadb.jdbc.Driver # only if spring_profiles=mysql
url: jdbc:mysql://${C2S_DB_HOST:localhost}:${C2S_DB_PORT:3306}/uaa # only if spring_profiles=mysql
username: root # only if spring_profiles=mysql
password: ${UAA_DB_PASSWORD:wtzhou} # only if spring_profiles=mysql
oauth:
clients:
admin:
secret: adminsecret
authorized-grant-types: client_credentials
scope: uaa.none
authorities: uaa.admin,clients.read,clients.write,clients.secret,scim.read,scim.write,clients.admin
cf: # this client is needed for cf cli and uaac cli to act on user's behalf
authorized-grant-types: implicit,password,refresh_token
scope: uaa.user,cloud_controller.read,cloud_controller.write,openid,password.write,scim.userids,cloud_controller.admin,scim.read,scim.write
authorities: uaa.none
autoapprove: true
patient-portal-ui:
authorized-grant-types: password
#secret: changeit
secret: loginsecret
scope: openid,phr.hie_read,phr.hie_write,phr.patient_read,pcm.provider_read,pcm.provider_create,pcm.provider_delete,pcm.consent_read,pcm.consent_create,pcm.consent_update,pcm.consent_delete,pcm.consent_sign,pcm.consent_revoke,pcm.clinicalDocument_read,pcm.clinicalDocument_create,pcm.clinicalDocument_delete,pcm.activity_read,ppUI.access,tryPolicy.clinicalDocument_read
authorities: uaa.resource
admin-portal-ui:
authorized-grant-types: password
secret: loginsecret
scope: openid,scim.write,scim.read,scim.create,phr.allPatientProfiles_read,phr.hie_write,phr.allPatients_read,phr.patient_read,registration.write,uaa.admin,patientUser.read,patientUser.write,adminUI.access,pep.patient_read
authorities: uaa.resource
patient-user:
secret: loginsecret
authorized-grant-types: client_credentials
scope: uaa.none
authorities: phr.patient_read,phr.allPatientProfiles_read,scim.write,scim.read,scim.create,uaa.admin
azhec-hie:
secret: loginsecret
authorized-grant-types: client_credentials
scope: uaa.none
authorities: pep.patient_read
sysadmin:
secret: loginsecret
authorized-grant-types: client_credentials
scope: uaa.none
authorities: patientUser.scope_assign,scim.write,scim.read,scim.create,uaa.admin
scim:
groups:
phr.hie_read: Access your health information
phr.hie_write: Add your health information
phr.patient_read: Access the patient details
pcm.provider_read: Access provider from list
pcm.provider_create: Create new provider
pcm.provider_delete: Delete provider from list
pcm.consent_read: Access and display your consent
pcm.consent_create: Add new consent
pcm.consent_update: Update current consent
pcm.consent_delete: Delete a consent
pcm.consent_sign: Sign consent
pcm.consent_revoke: Revoke current consent
pcm.clinicalDocument_read: Access and display clinical document
pcm.clinicalDocument_create: Create new clinical document
pcm.clinicalDocument_delete: Delete current clinical document
pcm.activity_read: Access the patient activity history
ppUI.access: Access patient portal UI
pep.patient_read: Access policy enforcement point
tryPolicy.clinicalDocument_read: View policies applied on clinical document
patientUser.scope_assign: Allows Sysadmin to assign scopes to users
users:
# Configure additional c2s staff admin(users) as:
# - EmailId | password | EmailId | FirstName | LastName | <Comma saperated list of permissions>
# For example: - consent2share#gmail.com|admin|consent2share#gmail.com|admin|admin|openid,scim.write,scim.read,scim.create,phr.allPatientProfiles_read,phr.hie_write,phr.allPatients_read,phr.patient_read,registration.write,uaa.admin,patientUser.read,patientUser.write,adminUI.access
- consent2share#gmail.com|admin|consent2share#gmail.com|admin|admin|openid,scim.write,scim.read,scim.create,phr.allPatientProfiles_read,phr.hie_write,phr.allPatients_read,phr.patient_read,registration.write,uaa.admin,patientUser.read,patientUser.write,adminUI.access
# C2S_APP_HOST and C2S_APP_PORT are related to edge server api
c2s:
uaa:
host: http://${C2S_APP_HOST:localhost}:${C2S_APP_PORT:81}/uaa
jwt:
token:
verification-key: |
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0m59l2u9iDnMbrXHfqkO
rn2dVQ3vfBJqcDuFUK03d+1PZGbVlNCqnkpIJ8syFppW8ljnWweP7+LiWpRoz0I7
fYb3d8TjhV86Y997Fl4DBrxgM6KTJOuE/uxnoDhZQ14LgOU2ckXjOzOdTsnGMKQB
LCl0vpcXBtFLMaSbpv1ozi8h7DJyVZ6EnFQZUWGdgTMhDrmqevfx95U/16c5WBDO
kqwIn7Glry9n9Suxygbf8g5AzpWcusZgDLIIZ7JTUldBb8qU2a0Dl4mvLZOn4wPo
jfj9Cw2QICsc5+Pwf21fP+hzf+1WSRHbnYv8uanRO0gZ8ekGaghM/2H6gqJbo2nI
JwIDAQAB
-----END PUBLIC KEY-----
signing-key: |
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA0m59l2u9iDnMbrXHfqkOrn2dVQ3vfBJqcDuFUK03d+1PZGbV
lNCqnkpIJ8syFppW8ljnWweP7+LiWpRoz0I7fYb3d8TjhV86Y997Fl4DBrxgM6KT
JOuE/uxnoDhZQ14LgOU2ckXjOzOdTsnGMKQBLCl0vpcXBtFLMaSbpv1ozi8h7DJy
VZ6EnFQZUWGdgTMhDrmqevfx95U/16c5WBDOkqwIn7Glry9n9Suxygbf8g5AzpWc
usZgDLIIZ7JTUldBb8qU2a0Dl4mvLZOn4wPojfj9Cw2QICsc5+Pwf21fP+hzf+1W
SRHbnYv8uanRO0gZ8ekGaghM/2H6gqJbo2nIJwIDAQABAoIBAHPV9rSfzllq16op
zoNetIJBC5aCcU4vJQBbA2wBrgMKUyXFpdSheQphgY7GP/BJTYtifRiS9RzsHAYY
pAlTQEQ9Q4RekZAdd5r6rlsFrUzL7Xj/CVjNfQyHPhPocNqwrkxp4KrO5eL06qcw
UzT7UtnoiCdSLI7IL0hIgJZP8J1uPNdXH+kkDEHE9xzU1q0vsi8nBLlim+ioYfEa
Q/Q/ovMNviLKVs+ZUz+wayglDbCzsevuU+dh3Gmfc98DJw6n6iClpd4fDPqvhxUO
BDeQT1mFeHxexDse/kH9nygxT6E4wlU1sw0TQANcT6sHReyHT1TlwnWlCQzoR3l2
RmkzUsECgYEA8W/VIkfyYdUd5ri+yJ3iLdYF2tDvkiuzVmJeA5AK2KO1fNc7cSPK
/sShHruc0WWZKWiR8Tp3d1XwA2rHMFHwC78RsTds+NpROs3Ya5sWd5mvmpEBbL+z
cl3AU9NLHVvsZjogmgI9HIMTTl4ld7GDsFMt0qlCDztqG6W/iguQCx8CgYEA3x/j
UkP45/PaFWd5c1DkWvmfmi9UxrIM7KeyBtDExGIkffwBMWFMCWm9DODw14bpnqAA
jH5AhQCzVYaXIdp12b+1+eOOckYHwzjWOFpJ3nLgNK3wi067jVp0N0UfgV5nfYw/
+YoHfYRCGsM91fowh7wLcyPPwmSAbQAKwbOZKfkCgYEAnccDdZ+m2iA3pitdIiVr
RaDzuoeHx/IfBHjMD2/2ZpS1aZwOEGXfppZA5KCeXokSimj31rjqkWXrr4/8E6u4
PzTiDvm1kPq60r7qi4eSKx6YD15rm/G7ByYVJbKTB+CmoDekToDgBt3xo+kKeyna
cUQqUdyieunM8bxja4ca3ukCgYAfrDAhomJ30qa3eRvFYcs4msysH2HiXq30/g0I
aKQ12FSjyZ0FvHEFuQvMAzZM8erByKarStSvzJyoXFWhyZgHE+6qDUJQOF6ruKq4
DyEDQb1P3Q0TSVbYRunOWrKRM6xvJvSB4LUVfSvBDsv9TumKqwfZDVFVn9yXHHVq
b6sjSQKBgDkcyYkAjpOHoG3XKMw06OE4OKpP9N6qU8uZOuA8ZF9ZyR7vFf4bCsKv
QH+xY/4h8tgL+eASz5QWhj8DItm8wYGI5lKJr8f36jk0JLPUXODyDAeN6ekXY9LI
fudkijw0dnh28LJqbkFF5wLNtATzyCfzjp+czrPMn9uqLNKt/iVD
-----END RSA PRIVATE KEY-----
I have been tried to find the reason for a long time, but I still cannot get it done. Could anyone help me to figure out what is the root cause for the error? Any reply will be very appreciated!

I think you need to add some authorities to the client (admin-portal-ui) you are using. Most likely adding oauth.login should do.
Please refer to sample client xml oauth-clients.xml on github uaa repo.
You may need something similar to the login client. In this xml, you can find many more authorities added to the login client. You can try adding all of them.
Another point you may want to check is the origin of the user, if you are trying to acquire token on behalf of the user without his password. In this case the origin must NOT be uaa

Related

Why is my Spring oauth server always returning the same access token?

I'm using Spring 4.3.8.RELEASE and spring-boot 1.5.3.RELEASE. I want to serve oauth access tokens to applications with the proper credentials. I'm using the org.springframework.security.oauth2.provider.token.store.JdbcTokenStore class to do this. However, I'm noticing that each time I connect with a client to my server that I have set up with OAuth, the server repeatedly returns the same access token, even after server restarts. My OAuth server configuration is below
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xmlns:sec="http://www.springframework.org/schema/security" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<http pattern="/oauth/token" create-session="stateless" authentication-manager-ref="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
<anonymous enabled="false" />
<http-basic entry-point-ref="clientAuthenticationEntryPoint" />
<!-- include this only if you need to authenticate clients via request parameters -->
<custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<!-- The OAuth2 protected resources are separated out into their own block
so we can deal with authorization and error handling separately. This isn't
mandatory, but it makes it easier to control the behaviour. -->
<http pattern="/oauth/(users|clients)/.*" request-matcher="regex"
create-session="stateless" entry-point-ref="oauthAuthenticationEntryPoint"
use-expressions="true" xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false" />
<intercept-url pattern="/oauth/users/([^/].*?)/tokens/.*"
access="#oauth2.clientHasRole('ROLE_CLIENT') and (hasRole('ROLE_USER') or #oauth2.isClient()) and #oauth2.hasScope('write')"
method="DELETE" />
<intercept-url pattern="/oauth/users/.*"
access="#oauth2.clientHasRole('ROLE_CLIENT') and (hasRole('ROLE_USER') or #oauth2.isClient()) and #oauth2.hasScope('read')"
method="GET" />
<intercept-url pattern="/oauth/clients/.*"
access="#oauth2.clientHasRole('ROLE_CLIENT') and #oauth2.isClient() and #oauth2.hasScope('read')"
method="GET" />
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
<expression-handler ref="oauthWebExpressionHandler" />
</http>
<!-- The OAuth2 protected resources are separated out into their own block
so we can deal with authorization and error handling separately. This isn't
mandatory, but it makes it easier to control the behaviour. -->
<http pattern="/me/**" create-session="never"
entry-point-ref="oauthAuthenticationEntryPoint"
access-decision-manager-ref="accessDecisionManager"
xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false" />
<intercept-url pattern="/me" access="ROLE_USER,SCOPE_READ" />
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<bean id="oauthAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="sparklr2" />
</bean>
<bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="sparklr2/client" />
<property name="typeName" value="Basic" />
</bean>
<bean id="oauthAccessDeniedHandler"
class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />
<bean id="clientCredentialsTokenEndpointFilter"
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="clientAuthenticationManager" />
</bean>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased"
xmlns="http://www.springframework.org/schema/beans">
<constructor-arg>
<list>
<bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter" />
<bean class="org.springframework.security.access.vote.RoleVoter" />
<bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
</list>
</constructor-arg>
</bean>
<authentication-manager id="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="clientDetailsUserService" />
</authentication-manager>
<authentication-manager alias="authenticationManager"
xmlns="http://www.springframework.org/schema/security">
<authentication-provider>
<user-service id="userDetailsService">
<user name="marissa" password="koala" authorities="ROLE_USER" />
<user name="paul" password="emu" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
<bean id="clientDetailsUserService"
class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails" />
</bean>
<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.store.JdbcTokenStore">
<constructor-arg ref="dataSource" />
<property name="authenticationKeyGenerator">
<bean class="org.springframework.security.oauth2.UniqueAuthenticationKeyGenerator" />
</property>
</bean>
<bean id="tokenServices"
class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore" />
<property name="tokenEnhancer" ref="tokenEnhancer" />
<property name="supportRefreshToken" value="true" />
<property name="clientDetailsService" ref="clientDetails" />
</bean>
<bean id="tokenEnhancer"
class="org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter" />
<bean id="requestFactory"
class="org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory">
<constructor-arg name="clientDetailsService" ref="clientDetails" />
</bean>
<bean id="approvalStore"
class="org.springframework.security.oauth2.provider.approval.TokenApprovalStore">
<property name="tokenStore" ref="tokenStore" />
</bean>
<oauth:authorization-server
client-details-service-ref="clientDetails" token-services-ref="tokenServices">
<oauth:client-credentials />
</oauth:authorization-server>
<oauth:resource-server id="resourceServerFilter" entry-point-ref="entry"
resource-id="myclientAssignment" token-services-ref="tokenServices" />
<bean id="entry" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<constructor-arg value="/assignment" />
</bean>
<context:property-placeholder location="classpath:application.properties"/>
<oauth:client-details-service id="clientDetails">
<oauth:client client-id="${myclient.client.id}"
authorized-grant-types="client_credentials" authorities="ROLE_CLIENT"
access-token-validity="30"
scope="read,write" secret="${myclient.client.secret}" />
</oauth:client-details-service>
<mvc:default-servlet-handler />
<oauth:expression-handler id="oauthExpressionHandler" />
<oauth:web-expression-handler id="oauthWebExpressionHandler" />
<http pattern="/api/**"
create-session="never"
entry-point-ref="oauthAuthenticationEntryPoint"
access-decision-manager-ref="accessDecisionManager"
xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false" />
<intercept-url pattern="/**"
access="IS_AUTHENTICATED_FULLY"/>
<custom-filter ref="resourceServerFilter"
before="PRE_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
</beans>
Here's the shell script I'm using to connect to my local server to retrieve the token ...
#!/bin/bash
ret=$(curl http://localhost:8080/myproject/oauth/token \
-u "myclientid:mysecret" \
-d "grant_type=client_credentials")
echo $ret > /tmp/out
cat /tmp/out
access_token=$( sed -e 's/^.*"access_token":"\([^"]*\)".*$/\1/' /tmp/out )
echo $access_token
Edit:
Per Hans' request, here is an example access token
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6WyJyZWFkIiwid3JpdGUiXSwiZXhwIjoxNDk2ODQ4NDAzLCJhdXRob3JpdGllcyI6WyJST0xFX0NMSUVOVCJdLCJqdGkiOiI4OGMxZjkzZC0wNmRhLTRmYTAtOTM1OS0yZWMxYzU5MWJlMGIiLCJjbGllbnRfaWQiOiJ6aW5jbGVhcm5pbmcifQ.Pf-rjPDj0ZhrNOYuhA0tK8lPLLCzlkqUuFFjb48xskA
and here is a second access token
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6WyJyZWFkIiwid3JpdGUiXSwiZXhwIjoxNDk2OTUzNTg0LCJhdXRob3JpdGllcyI6WyJST0xFX0NMSUVOVCJdLCJqdGkiOiIxM2I5M2M4Ni05MmIwLTQyY2UtYjFkNS1lZjRiNmZhNzJkMzgiLCJjbGllbnRfaWQiOiJ6aW5jbGVhcm5pbmcifQ.GfSHA_JcQg2WHYCI81lunMFIhxdX6REc4goshB2Lck0
This is sample regular access token which when issued will have 30 seconds expiration for your configuration.
You should see the info message (Failed to find access token for token) at the time a new token is issued.
{
"access_token": "e057a4f3-9872-4b97-803e-938ad6ef32db",
"token_type": "bearer",
"refresh_token": "f9a7ea9a-0fd1-45a9-b8ae-de87eaf61787",
"expires_in": 30,
"scope": "read write"
}
This is expected behavior as spring looks into database to verify if the access token for the authentication is already issued.
Subsequent requests until the expiry of token (30s) will not show the message. This message will show up again after old access token is expired and when new token is issued and it continues.
The below line is where that info message is displayed from
https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/provider/token/store/JdbcTokenStore.java#L168
Refresh token is set to expire in 30 days by default. The similar log message will appear again when the refresh token expires.
It should work similar for JWT access token too.
This is the sequences of log messages when a new token is issued when you run the application in DEBUG logging level.
2017-06-06 14:06:51.339 DEBUG 28732 --- [nio-9191-exec-1] o.s.s.o.p.token.store.JdbcTokenStore : Failed to find access token for authentication org.springframework.security.oauth2.provider.OAuth2Authentication#8e69d9c0: Principal: org.springframework.security.core.userdetails.User#586034f: Username: admin; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ADMIN,ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_ADMIN, ROLE_USER
2017-06-06 14:06:51.346 DEBUG 28732 --- [nio-9191-exec-1] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL query
2017-06-06 14:06:51.346 DEBUG 28732 --- [nio-9191-exec-1] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [select token_id, token from oauth_access_token where token_id = ?]
2017-06-06 14:06:51.347 INFO 28732 --- [nio-9191-exec-1] o.s.s.o.p.token.store.JdbcTokenStore : Failed to find access token for token e057a4f3-9872-4b97-803e-938ad6ef32db
2017-06-06 14:06:51.442 DEBUG 28732 --- [nio-9191-exec-1] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update
2017-06-06 14:06:51.443 DEBUG 28732 --- [nio-9191-exec-1] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [insert into oauth_access_token (token_id, token, authentication_id, user_name, client_id, authentication, refresh_token) values (?, ?, ?, ?, ?, ?, ?)]
2017-06-06 14:06:51.450 DEBUG 28732 --- [nio-9191-exec-1] o.s.jdbc.core.JdbcTemplate : SQL update affected 1 rows
2017-06-06 14:06:51.452 DEBUG 28732 --- [nio-9191-exec-1] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL update
2017-06-06 14:06:51.452 DEBUG 28732 --- [nio-9191-exec-1] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [insert into oauth_refresh_token (token_id, token, authentication) values (?, ?, ?)]
2017-06-06 14:06:51.455 DEBUG 28732 --- [nio-9191-exec-1] o.s.jdbc.core.JdbcTemplate : SQL update affected 1 rows
Why i am getting same access token for multiple login request?
Ashwani has given answer like below in this post
Access Tokens have fixed Life-Time.
Until that period has not expires, access token remains the same.
During that period if you request access token you will receive the same string but will have reset expiration. It would only happen if
Location, Password etc are exactly same as previous request.
Otherwise new token generated. Sometimes Salesforce resets the
expiration time for last expired token and return in response.
Short-lived access tokens and long-lived refresh tokens
There is no way to expire those tokens directly, so instead, the tokens are issued with a short expiration time so that the application is forced to continually refresh them, giving the service a chance to revoke an application’s access if needed.
#Dave, As you have told that, there is no expiry field, so it is non-expiring access token.
Non-expiring access tokens
Non-expiring access tokens are the easiest method for developers. If you choose this option, it is important to consider the trade-offs you are making.
It isn’t practical to use self-encoded tokens if you want to be able to revoke them arbitrarily. As such, you’ll need to store these tokens in some sort of database, so they can be deleted or marked as invalid as needed.
Note that even if the service intends on issuing non-expiring access tokens for normal use, you’ll still need to provide a mechanism to expire them under exceptional circumstances, such as if the user explicitly wants to revoke an application’s access, or if a user account is deleted.
Non-expiring access tokens are much easier for developers testing their own applications. You can even pre-generate one or more non-expiring access tokens for developers and show it to them on the application details screen. This way they can immediately start making API requests with the token, and not worry about setting up an OAuth flow in order to start testing your API.
In summary, use non-expiring access tokens when:
you have a mechanism to revoke access tokens arbitrarily
you don’t have a huge risk if tokens are leaked
you want to provide an easy authentication mechanism to your
developers
you want third-party applications to have offline access to users’
data
Resource Link: Acess token lifetime
How to refresh access token? Rules are given here: https://www.oauth.com/oauth2-servers/access-tokens/refreshing-access-tokens/
How to issue an access token are given here:
+----------+
| Resource |
| Owner |
| |
+----------+
v
| Resource Owner
(A) Password Credentials
|
v
+---------+ +---------------+
| |>--(B)---- Resource Owner ------->| |
| | Password Credentials | Authorization |
| Client | | Server |
| |<--(C)---- Access Token ---------<| |
| | (w/ Optional Refresh Token) | |
+---------+ +---------------+
Figure 5: Resource Owner Password Credentials Flow
The flow illustrated in Figure 5 includes the following steps:
(A) The resource owner provides the client with its username and
password.
(B) The client requests an access token from the authorization
server's token endpoint by including the credentials received
from the resource owner. When making the request, the client
authenticates with the authorization server.
(C) The authorization server authenticates the client and validates
the resource owner credentials, and if valid, issues an access
token.
The authorization server MUST follow the rules:
o require client authentication for confidential clients or for any
client that was issued client credentials (or with other
authentication requirements),
o authenticate the client if client authentication is included, and
o validate the resource owner password credentials using its
existing password validation algorithm.
Resource Link: https://www.rfc-editor.org/rfc/rfc6749#page-47
In your configuration you use a JdbcTokenStore :
So, you have to check the table oauth_client_details : you must have a row with a column access_token_validity where you can change in live the duration in seconds.
Another solution is to delete that row and redeploy your application. Your configuration will create the row again with the value you specified in your configuration and that you were speaking about in the conversation.
I know it is very late to post an answer to this question but here is what I think should be considered.
When configuring an Authorization server, one of the parameters is the accessTokenValiditySeconds.
the point here is that it is your solution:
Here is an example of configuring the Authorization server.
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient(ParamsConfig.TRUSTED_CLIENT_ID)
.secret(passwordEncoder.encode(ParamsConfig.TRUSTED_CLIENT_SECRET))
.accessTokenValiditySeconds(10)
.scopes(ParamsConfig.OAUTH_SECURITY_SCOPE)
.authorizedGrantTypes(ParamsConfig.OAUTH_AUTHORIZATION_GRANT_TYPE)
.authorities(ParamsConfig.OAUTH_SECURITY_AUTHORITIES)
.resourceIds(ParamsConfig.OAUTH_SECURITY_RESOURCE_ID);
}
See the accessTokenValiditySeconds that describes two things:
1 - till what time this access token will be valid.
2 - till what time you will be getting the same Access token if you request for an access token.
Note:
This configuration is in Java not xml.
In your case, it should be access-token-validity.

How to make the refresh token life long valid and issue a new refresh token each time a new refresh_token grant_type comes in spring security oauth2

I am using spring security oauth2 for authentication for my android application clients.When the client request comes with grant_type as password the server issues the access token and refresh token.If the access token expires i can issue a new access token by sending a request with grant_type as refresh_token.Now what will i do if my refresh token expires?I dont want to prompt the users to authenticate again using his credentials.So is there a way to issue a new refresh token along with the new access token? or is there any provision to issue a refresh token with infinite validity or by sending a refresh token with single time use only and refresh the refresh token in each refresh_token grant_type request.Below is my configuration file for spring security oauth2.
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:sec="http://www.springframework.org/schema/security" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd ">
<!-- This is default url to get a token from OAuth -->
<http pattern="/oauth/token" create-session="stateless"
authentication-manager-ref="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
<anonymous enabled="false" />
<http-basic entry-point-ref="clientAuthenticationEntryPoint" />
<!-- include this only if you need to authenticate clients via request
parameters -->
<custom-filter ref="clientCredentialsTokenEndpointFilter"
after="BASIC_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<!-- This is where we tells spring security what URL should be protected
and what roles have access to them -->
<http pattern="/protected/**" create-session="never"
entry-point-ref="oauthAuthenticationEntryPoint"
access-decision-manager-ref="accessDecisionManager"
xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false" />
<intercept-url pattern="/protected/**" access="ROLE_APP" />
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<bean id="oauthAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="test" />
</bean>
<bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="test/client" />
<property name="typeName" value="Basic" />
</bean>
<bean id="oauthAccessDeniedHandler"
class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />
<bean id="clientCredentialsTokenEndpointFilter"
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="clientAuthenticationManager" />
</bean>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased"
xmlns="http://www.springframework.org/schema/beans">
<constructor-arg>
<list>
<bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter" />
<bean class="org.springframework.security.access.vote.RoleVoter" />
<bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
</list>
</constructor-arg>
</bean>
<authentication-manager id="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="clientDetailsUserService" />
</authentication-manager>
<authentication-manager alias="authenticationManager"
xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="userService">
</authentication-provider>
</authentication-manager>
<bean id="userService"
class="com.example.myproject.ser.UserService">
</bean>
<bean id="clientDetailsUserService"
class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails" />
</bean>
<!-- This defined token store, we have used inmemory tokenstore for now
but this can be changed to a user defined one -->
<bean id="tokenStore"
class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />
<!-- This is where we defined token based configurations, token validity
and other things -->
<bean id="tokenServices"
class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore" />
<property name="supportRefreshToken" value="true" />
<property name="accessTokenValiditySeconds" value="120" /> <!-- 2 hour 3600 -->
<property name="refreshTokenValiditySeconds" value="420"></property> <!-- 2 month 5270400 -->
<property name="clientDetailsService" ref="clientDetails" />
</bean>
<bean id="userApprovalHandler"
class="org.springframework.security.oauth2.provider.approval.TokenServicesUserApprovalHandler">
<property name="tokenServices" ref="tokenServices" />
</bean>
<oauth:authorization-server
client-details-service-ref="clientDetails" token-services-ref="tokenServices"
user-approval-handler-ref="userApprovalHandler">
<oauth:authorization-code />
<oauth:implicit />
<oauth:refresh-token />
<oauth:client-credentials />
<oauth:password />
</oauth:authorization-server>
<oauth:resource-server id="resourceServerFilter"
resource-id="test" token-services-ref="tokenServices" />
<bean id="clientDetails"
class="com.example.myproject.ser.ClientService">
</bean>
<sec:global-method-security
pre-post-annotations="enabled" proxy-target-class="true">
<!--you could also wire in the expression handler up at the layer of the
http filters. See https://jira.springsource.org/browse/SEC-1452 -->
<sec:expression-handler ref="oauthExpressionHandler" />
</sec:global-method-security>
<oauth:expression-handler id="oauthExpressionHandler" />
<oauth:web-expression-handler id="oauthWebExpressionHandler" />
</beans>
In my android application i have the provision to authenticate the same user from multiple devices.That is one can authenticate in any device if already he is authenticated in other device.So the solution don't affect this case.
You can set validity period for the refresh token either at the client level (see org.springframework.security.oauth2.provider.ClientDetails and org.springframework.security.oauth2.provider.ClientDetailsService).
You'll need to set this on the client as it's loaded by the client details service.
public classs MyClientDetailsService implements ClientDetailsService {
#Override
public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
BaseClientDetails client = new BaseClientDetails();
client.setRefreshTokenValiditySeconds(Integer.MAX_VALUE);
...
return client;
}
}
Alternatively, you can set a default validity on org.springframework.security.oauth2.provider.token.DefaultTokenServices (assuming that is the implementation that you are using in your server) in your authorisation server configuration. You can do this by adding the following method to your authorisation server configuration class.
#Bean
public AuthorizationServerTokenServices authorizationServerTokenServices() throws Exception {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(tokenStore);
tokenServices.setSupportRefreshToken(true);
tokenServices.setClientDetailsService(clientDetailsService);
tokenServices.setRefreshTokenValiditySeconds(Integer.MAX_VALUE);
return tokenServices;
}
Once that refresh token has expired though, I believe the only way to obtain a new one is for the user to re-authenticate.
According to the source code for spring-security-oauth in the DefaultTokenServices passing a value less or equal to zero as the validity of the refresh token should be enough to make it last forever. Check it out here.
Then the code in the authorisation server configuration should be like this:
#Bean
fun tokenServices(): DefaultTokenServices {
val defaultTokenServices = DefaultTokenServices()
defaultTokenServices.setTokenStore(tokenStore())
defaultTokenServices.setRefreshTokenValiditySeconds(0)
return defaultTokenServices
}
Or if you have a JdbcClientDetailsService you can set the refresh token expiry in the oauth_client_detailstable.

Spring Boot OAuth2 SSO

I'm not an expert in Spring Security..
I have one single angularjs app, which has OAuth2 based authentication and authorization.
Now I need to add additional app, but users and passwords should be the same for both apps.
So.. I need to have one sso server and two resource servers.
I want to implement that with modern spring boot.
Currently I authenticate users against /oauth/token with grant_type=password
I wonder if there are some samples of SSO and Resource servers that would allow me to authenticate users against http://sso.host/oauth/token?username=someuser&password=somepass&grant_type=password
so.. I will get my acccess and refresh tokens as the result of success authentication.
And access token would be good to use against http://resource.host/rest/someresource
while refresh token would be good to get access_tokens at http://sso.host/oauth/token?grant_type=refresh
I don't want my apps to be redirected to any urls..
I don't need any login forms, just json responses.
Here is my current spting-security-oauth.xml config:
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xmlns:context="http://www.springframework.org/schema/context" xmlns:sec="http://www.springframework.org/schema/security" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd "><beans>
<authorization-server client-details-service-ref="clientDetails" token-services-ref="tokenServices" xmlns="http://www.springframework.org/schema/security/oauth2">
<refresh-token />
<client-credentials />
<password authentication-manager-ref="userAuthenticationManager" disabled="false"/>
</authorization-server>
<authentication-manager id="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="clientDetailsUserService" />
</authentication-manager>
<authentication-manager alias="userAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider>
<user-service>
<user name="username" password="password" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
<http pattern="/oauth/token" create-session="stateless" authentication-manager-ref="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
<anonymous enabled="false" />
<http-basic entry-point-ref="clientAuthenticationEntryPoint" />
<custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<oauth:resource-server id="resourceServerFilter" resource-id="rest_server" token-services-ref="tokenServices" />
<oauth:client-details-service id="clientDetails">
<oauth:client client-id="the_client" secret="" scope="read,write" authorized-grant-types="password,refresh_token,client_credentials" authorities="ROLE_USER"/>
</oauth:client-details-service>
<http pattern="/rest/**" create-session="never" entry-point-ref="oauthAuthenticationEntryPoint" access-decision-manager-ref="accessDecisionManager" xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false" />
<intercept-url pattern="/rest/**" access="ROLE_USER" />
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore" />
<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore" />
<property name="supportRefreshToken" value="true" />
<property name="clientDetailsService" ref="clientDetails" />
<property name="accessTokenValiditySeconds" value="300" />
<property name="refreshTokenValiditySeconds" value="3600" />
</bean>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased">
<constructor-arg>
<list>
<bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter" />
<bean class="org.springframework.security.access.vote.RoleVoter" />
<bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
</list>
</constructor-arg>
</bean>
<bean id="oauthAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="test" />
</bean>
<bean id="clientAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="theRealm/client" />
<property name="typeName" value="Basic" />
</bean>
<bean id="clientCredentialsTokenEndpointFilter" class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="clientAuthenticationManager" />
</bean>
<bean id="clientDetailsUserService" class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails" />
</bean>
<bean id="oauthAccessDeniedHandler" class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />
<sec:global-method-security pre-post-annotations="enabled" proxy-target-class="true">
<sec:expression-handler ref="oauthExpressionHandler" />
</sec:global-method-security>
<oauth:expression-handler id="oauthExpressionHandler" />
<oauth:web-expression-handler id="oauthWebExpressionHandler" />
I don't think you can naturally do SSO with the password grant type. You're probably best with the authorization code flow. Oauth2 sso happens because both client apps check for the authenticated session on the authorization server and, if one has already logged in, the second app doesn't need to provide credentials again.
https://spring.io/blog/2015/02/03/sso-with-oauth2-angular-js-and-spring-security-part-v is a good example with angularjs and spring boot.
That is, if you want SSO, I think you'll need redirection to the authorization server for initial login.

Redirect to login page after login

i have a web application in spring which uses spring security. After successful deploy login page come. after login it again redirect to login page.
This is my securityContext.xml
<!-- enable method-level security via annotation -->
<sec:global-method-security secured-annotations="enabled" jsr250-annotations="disabled"/>
<!-- secure the web layer -->
<sec:http pattern="/login.jsp" security="none" />
<sec:http pattern="/js/**" security="none" />
<sec:http pattern="/scripts/**" security="none" />
<sec:http pattern="/favicon.ico" security="none" />
<sec:http pattern="/styles/**" security="none" />
<sec:http pattern="/images/**" security="none" />
<sec:http pattern="/qlogin.jsp" security="none" />
<sec:http pattern="/qloginWait/**" security="none" />
<sec:http pattern="/contract/ServiceContractPDFView.jsp" security="none" />
<sec:http pattern="/admin/unsubscribe_sbpqm_newsletter.jsp" security="none" />
<sec:http pattern="/admin/subscription_thankyou.jsp" security="none" />
<sec:http pattern="/admin/related_analysts.jsp" security="none" />
<sec:http entry-point-ref="myAuthenticationEntryPoint" use-expressions="true">
<sec:session-management session-fixation-protection="newSession">
</sec:session-management>
<sec:csrf disabled="true"/>
<sec:custom-filter position="FORM_LOGIN_FILTER" ref="customizedFormLoginFilter"/>
<sec:custom-filter after="FORM_LOGIN_FILTER" ref="rememberMeProcessingFilter"/>
<sec:custom-filter after="REMEMBER_ME_FILTER" ref="logoutFilter"/>
<sec:intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
<sec:anonymous username="anonymousUser" granted-authority="ROLE_ANONYMOUS"/>
<!-- <sec:custom-filter before="FILTER_SECURITY_INTERCEPTOR" ref="singleSignOnFilter"/> -->
</sec:http>
<!--name of my authenticationManager is authenticationManager-->
<sec:authentication-manager alias="authenticationManager">
<sec:authentication-provider user-service-ref="myUserDetailsService" />
</sec:authentication-manager>
<bean id="customizedFormLoginFilter" class="com.prop.test.security.CustomAuthenticationProcessingFilter" >
<!--Here it is the custom authenticationManager, login magic goes here -->
<property name="authenticationManager" ref="myAuthenticationManager"/>
<property name="rememberMeServices" ref="rememberMeServices" />
<property name="allowSessionCreation" value="true" />
<property name="authenticationFailureHandler" ref="failureHandler"/>
<property name="authenticationSuccessHandler" ref="successHandler"/>
</bean>
<bean id="myAuthenticationManager" class="com.prop.test.security.CustomAuthenticationManager" />
<bean id="loggerListener" class="org.springframework.security.access.event.LoggerListener"/>
<!--My authentication entry point, can be replaced easily if we are doing custom commence of invalid auths.-->
<bean id="myAuthenticationEntryPoint"
class="com.prop.test.security.CustomAuthenticationEntryPoint" >
<constructor-arg value="/j_spring_security_check"/>
</bean>
<bean id="successHandler" class="com.prop.test.security.CustomSavedRequestAwareAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/indexCustomer.jsp"/>
</bean>
<bean id="failureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/login.jsp?login_error=1"/>
</bean>
<!-- Override RememberMeProcessingFilter to allow application of other business logic (update login count when user returns to the site -->
<bean id="rememberMeProcessingFilter" class="com.prop.test.security.CustomRememberMeProcessingFilter">
<constructor-arg ref="authenticationManager"/>
<constructor-arg ref="rememberMeServices"/>
</bean>
<bean id="signleSignOnService" class="com.prop.sage.sso.dynamo.SsoDbStorage">
</bean>
<bean id="singleSignOnFilter"
class="com.prop.test.spring.SingleSignOnFilter">
<property name="signleSignOnService" ref="signleSignOnService"/>
<!--<property name="authenticationProviderFacade" ref="authenticationProviderFacade"/>-->
<property name="userService" ref="propUserServiceImpl"/>
<property name="ssoUserUrl">
<value>/sso</value>
</property>
<!-- Code Review Starts -->
<property name="ssoTargetUrl">
<value>/search/ServiceContractSearch.do</value>
</property>
<!-- Code Review Ends -->
<property name="ssoFailureUrl">
<value>/login.jsp</value>
</property>
<property name="order" value="123456"/>
</bean>
<!-- Remember me Authentication Defines which remember me implementation to use - in this case using a database table to log 'remembered' tokens -->
<bean id="myUserDetailsService" class="com.prop.test.security.CustomUserDetailsService" > </bean>
<bean id="rememberMeServices" class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices">
<constructor-arg value="springRocks"/>
<constructor-arg ref="myUserDetailsService"/>
<constructor-arg ref="jdbcTokenRepository"/>
</bean>
<!-- Uses a database table to maintain a set of persistent login data -->
<bean id="jdbcTokenRepository" class="org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl">
<property name="createTableOnStartup" value="false" />
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="rememberMeAuthenticationProvider" class="org.springframework.security.authentication.RememberMeAuthenticationProvider">
<constructor-arg value="springRocks"/>
</bean>
<bean id="securityContextLogoutHandler" class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler" >
<property name="invalidateHttpSession" value="true" />
</bean>
<bean id="mySecurityContextHandler" class="com.prop.test.security.CustomSecurityContextLogoutHandler"/>
<bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<constructor-arg value="/login.jsp" />
<constructor-arg>
<list>
<ref bean="mySecurityContextHandler" />
<ref bean="rememberMeServices" />
<ref bean="securityContextLogoutHandler" />
</list>
</constructor-arg>
</bean>
<bean id="authenticationLoggerListener" class="org.springframework.security.access.event.LoggerListener"/>
<bean id="_sessionFixationProtectionFilter" class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy">
<property name="migrateSessionAttributes" value="true" />
</bean>
Logs in logger file -
org.springframework.security.access.event.LoggerListener - Security authorization failed due to: org.springframework.security.access.AccessDeniedException: Access is denied; authenticated principal: org.springframework.security.authentication.AnonymousAuthenticationToken#90579aae: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#2eb76: RemoteIpAddress: 127.0.0.1; SessionId: 6C81F0D37667C08742208FC0B8BA3E86; Granted Authorities: ROLE_ANONYMOUS; secure object: FilterInvocation: URL: /j_spring_security_check; configuration attributes: [hasRole('ROLE_USER')]
According to your config, only ROLE_USER has access to all pages /**
And you tried to login as anonymousUser whose granted authority is ROLE_ANONYMOUS
Hence you can't go forward with anonymousUser and access is denied.
So if you wish you can allow access for anonymousUser as access="hasAnyRole(ROLE_USER,ROLE_ANONYMOUS)"
<sec:intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
<sec:anonymous username="anonymousUser" granted-authority="ROLE_ANONYMOUS"/>

Token URL fails with spring security oauth2

I'm trying to get a oauth2 configuration for securing my webapp and only allowing trusted clients with provided user credentials to access the app.
This is what I have so far
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oauth="http://www.springframework.org/schema/security/oauth2" xmlns:sec="http://www.springframework.org/schema/security"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<http pattern="/oauth/token" create-session="stateless" authentication-manager-ref="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
<anonymous enabled="false" />
<http-basic entry-point-ref="clientAuthenticationEntryPoint" />
<!-- include this only if you need to authenticate clients via request parameters -->
<custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<!-- The OAuth2 protected resources are separated out into their own block so we can deal with authorization and error handling
separately. This isn't mandatory, but it makes it easier to control the behaviour. -->
<http request-matcher="regex" create-session="stateless" entry-point-ref="oauthAuthenticationEntryPoint"
xmlns="http://www.springframework.org/schema/security">
<!-- <anonymous enabled="false" /> -->
<intercept-url pattern="/api/register/.*" access="ROLE_CLIENT" />
<intercept-url pattern="/api/.*" access="ROLE_USER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
<expression-handler ref="oauthWebExpressionHandler" />
</http>
<bean id="oauthAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="qeep" />
</bean>
<bean id="clientAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="qeep/client" />
</bean>
<bean id="oauthAccessDeniedHandler" class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />
<authentication-manager alias="authenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="qeepUserDetailsService" />
</authentication-manager>
<bean id="myUserDetailsService" class="com.example.core.web.rest.auth.QeepUserDetailsService"/>
<bean id="tokenStore" class="com.example.core.web.rest.auth.QeepTokenStore" />
<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore" />
<property name="supportRefreshToken" value="true" />
<property name="clientDetailsService" ref="clientDetails" />
</bean>
<authentication-manager id="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="clientDetailsUserService" />
</authentication-manager>
<bean id="clientDetailsUserService" class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails" />
</bean>
<bean id="clientCredentialsTokenEndpointFilter" class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="clientAuthenticationManager" />
</bean>
<oauth:client-details-service id="clientDetails">
<oauth:client client-id="my-trusted-client-with-secret" authorized-grant-types="password,authorization_code,refresh_token,implicit"
secret="somesecret" authorities="ROLE_CLIENT, ROLE_TRUSTED_CLIENT" />
</oauth:client-details-service>
<oauth:authorization-server client-details-service-ref="clientDetails" token-services-ref="tokenServices">
<oauth:authorization-code />
<oauth:implicit />
<oauth:refresh-token />
<oauth:client-credentials />
<oauth:password />
</oauth:authorization-server>
<sec:global-method-security pre-post-annotations="enabled" proxy-target-class="true">
<!--you could also wire in the expression handler up at the layer of the http filters. See https://jira.springsource.org/browse/SEC-1452 -->
<sec:expression-handler ref="oauthExpressionHandler" />
</sec:global-method-security>
<oauth:expression-handler id="oauthExpressionHandler" />
<oauth:web-expression-handler id="oauthWebExpressionHandler" />
</beans>
If I access /oauth/token using curl, I get a client authorization request which I get through using the configured client credentials. But after this /oauth/token only returns 404 - Not found. I've tried different stuff for the last hours without any success.
I extracted the configuration from the sparklr/tonr sample of oauth2 1.0.5 which I used because we are still on spring 3.2.
The same test works fine in the sparklr-Sample-webapp.
EDIT
The actual curl url is the following:
curl -v -H "Authorization: Basic bXktdHJ1c3RlZC1jbGllbnQtd2l0aC1zZWNyZXQ6c29tZXNlY3JldA==" "http://localhost:8084/core/oauth/token"
Without the Authorization-Header I get a 401 asking for the client authentication as configured ("my-trusted-client-with-secret" and "somesecret") but with the added authorization header I just get the 404 - Not found. If I test the same with the sparklr-Sample I get an error asking for the grant-type after adding the Basic-Auth-Header like above which is what I would expect.
I hope this makes a bit clearer.
Any ideas what's wrong with my configuration?
The DispatcherServlet was mapped to the wrong url, I broke it while trying to fix an issue which I had first. The Dispatcher-Servlet is mapped to core/api and the token service first was mapped to core/api/oauth/token which I later changed to core/oauth/token but I forgot to change the DispatcherServlet. Thanks, Dave for the hint!

Resources