My Java Spring Authentication and Authorization Server is working.
I want to solve the errors in the requests I send from a client according to the OAuth2 flow. But none of the errors I get are detailed. For example, this request sent to /oauth2/authorize:
https://MY_DOMAIN/authorize?
response_type=code&
client_id=MY_CLIENT_ID&
redirect_uri=MY_CALLBACK_URL&
scope=SCOPE&
state=STATE
Gives the following error after I enter credentials:
My goal is not to resolve the error here, but there are different errors I get like this and I need to see a more informative error message so I can debug them all.
The console also has a non-informative output that goes like this:
...
2022-08-15 15:52:33.739 DEBUG 50827 --- [nio-9000-exec-4] s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request
2022-08-15 15:52:33.739 DEBUG 50827 --- [nio-9000-exec-4] o.a.c.c.C.[Tomcat].[localhost] : Processing ErrorPage[errorCode=0, location=/error]
2022-08-15 15:52:33.739 DEBUG 50827 --- [nio-9000-exec-4] o.s.security.web.FilterChainProxy : Securing GET /error?protocol=oauth2&response_type=code&access_type&client_id=articles-client&redirect_uri=http%3A%2F%2F127.0.0.1%3A3000%2Flms%2Flogin&scope=openid%20articles.read&state=XqqDv6wx6O&code_challenge_method=plain&code_challenge=e964fe0c4b609ef3cf29658efc6077e7feb591f78c458c2092aa56c9
...
Related
I have a problem where I cannot acces any url while logged in on an accont with a custom defined ROLE.
To create the new roles for my app, I added my new roles in the AuthoritiesConstants class and in authorities.csv.
Then I manually inserted my new desired roles : ROLE_STUDENT and ROLE_PROFESOR in my h2-database.
Then I logged in on the admin account and tried and succeeded to create a new user with the ROLE_STUDENT.
Then I logged on to this new account and tried to access http://localhost:9000/api/users to get the full list of users.
I got the following error :
2020-03-19 10:59:05.687 DEBUG 13892 --- [ XNIO-1 task-15] base.aop.logging.LoggingAspect : Enter: base.repository.CustomAuditEventRepository.add() with argument[s] = [AuditEvent [timestamp=2020-03-19T08:59:05.686Z, principal=anonymousUser, type=AUTHORIZATION_FAILURE, data={details=org.springframework.security.web.authentication.WebAuthenticationDetails#b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null, type=org.springframework.security.access.AccessDeniedException, message=Access is denied}]]
2020-03-19 10:59:05.691 DEBUG 13892 --- [ XNIO-1 task-15] base.aop.logging.LoggingAspect : Exit: base.repository.CustomAuditEventRepository.add() with result = null
2020-03-19 10:59:05.693 WARN 13892 --- [ XNIO-1 task-15] o.z.problem.spring.common.AdviceTraits : Unauthorized: Full authentication is required to access this resource
2020-03-19 10:59:05.695 WARN 13892 --- [ XNIO-1 task-15] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [org.springframework.security.authentication.InsufficientAuthenticationException: Full authentication is required to access this resource]
In my SecurityConfiguration class, this url falls under .antMatchers("/api/**").authenticated(). So I was supposed to be able to access it from any account, as long as I am logged in.
To my dismay, it seems I cannot access any URL, apart from the home page, from this account. I manually checked my database to see if the user has been created and has the correct role. All is well there.
Can someone help me solve this ?
You have to open the routes to the new roles too, this is done on the client side. This is more or less how it looks if you use angular.
The home component is open to anyone as you can see in the file home.route.ts.
export const HOME_ROUTE: Route = {
path: '',
component: HomeComponent,
data: {
authorities: [], // <- Empty, so anyone can access the home
pageTitle: 'home.title'
}
};
On the other hand, if you want to grant access to a new role in a regular component, you'll have to add it to the valid authorities array in your [entity-name].route.ts.
export const fooRoute: Routes = [
{
...
data: {
authorities: ['ROLE_STUDENT', 'ROLE_PROFESOR'],
...
},
...
That gives access to any user who has either ROLE_STUDENT or ROLE_PROFESOR, but not regular users (who only have ROLE_USER). This was just an example.
In any case, if I understood your question correctly, you were trying to access an api/... mapping directly in your browser. That's not a good idea and it's good that it fails since the client usually adds stuff to most requests so that they are properly handled and validated by the server (XSRF, auth token, ...).
im trying to to read a value from Google-Cloud storage from my Spring application. I use the Spring Cloud GCP extension to work with Google Cloud Storage.
My Pom.xml for the gcp dependency:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-gcp-starter-storage</artifactId>
<version>1.1.2.RELEASE</version>
</dependency>
When i try to read a file from my rest-endpoint i get the exception(at the end of my answer) that somehow that my token could not be refreshed ? Where i can set my clientId or is there something else going on ? I used the code from the sample application which is provided by pivotal and google.
#RestController
public class GCloudStorageController {
#Value("gs://test_files_test/test.txt")
private Resource gcsFile;
#RequestMapping(value = "/cloud", method = RequestMethod.GET)
public String readGcsFile() throws IOException {
return StreamUtils.copyToString(
this.gcsFile.getInputStream(),
Charset.defaultCharset()) + "\n";
}
#RequestMapping(value = "/cloud", method = RequestMethod.POST)
String writeGcs(#RequestBody String data) throws IOException {
try (OutputStream os = ((WritableResource) this.gcsFile).getOutputStream()) {
os.write(data.getBytes());
}
return "file was updated\n";
}
}
2019-08-20 20:27:02.555 DEBUG 12348 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Failed to complete request: com.google.cloud.storage.StorageException: 400 Bad Request
{
"error": "invalid_grant",
"error_description": "Bad Request"
}
2019-08-20 20:27:02.556 DEBUG 12348 --- [nio-8080-exec-1] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#24f1dc0f
2019-08-20 20:27:02.557 DEBUG 12348 --- [nio-8080-exec-1] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2019-08-20 20:27:02.557 DEBUG 12348 --- [nio-8080-exec-1] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2019-08-20 20:27:02.563 ERROR 12348 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is com.google.cloud.storage.StorageException: 400 Bad Request
{
"error": "invalid_grant",
"error_description": "Bad Request"
}] with root cause
com.google.api.client.http.HttpResponseException: 400 Bad Request
{
"error": "invalid_grant",
"error_description": "Bad Request"
}
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1094) ~[google-http-client-1.30.1.jar:na]
at com.google.auth.oauth2.UserCredentials.refreshAccessToken(UserCredentials.java:193) ~[google-auth-library-oauth2-http-0.16.1.jar:na]
at com.google.auth.oauth2.OAuth2Credentials.refresh(OAuth2Credentials.java:165) ~[google-auth-library-oauth2-http-0.16.1.jar:na]
at com.google.auth.oauth2.OAuth2Credentials.getRequestMetadata(OAuth2Credentials.java:151) ~[google-auth-library-oauth2-http-0.16.1.jar:na]
at com.google.auth.http.HttpCredentialsAdapter.initialize(HttpCredentialsAdapter.java:96) ~[google-auth-library-oauth2-http-0.16.1.jar:na]
at com.google.cloud.http.HttpTransportOptions$1.initialize(HttpTransportOptions.java:159) ~[google-cloud-core-http-1.79.0.jar:1.79.0]
at com.google.cloud.http.CensusHttpModule$CensusHttpRequestInitializer.initialize(CensusHttpModule.java:109) ~[google-cloud-core-http-1.79.0.jar:1.79.0]
at com.google.api.client.http.HttpRequestFactory.buildRequest(HttpRequestFactory.java:88) ~[google-http-client-1.30.1.jar:na]
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.buildHttpRequest(AbstractGoogleClientRequest.java:430) ~[google-api-client-1.30.1.jar:1.30.1]
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:549) ~[google-api-client-1.30.1.jar:1.30.1]
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:482) ~[google-api-client-1.30.1.jar:1.30.1]
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:599) ~[google-api-client-1.30.1.jar:1.30.1]
at com.google.cloud.storage.spi.v1.HttpStorageRpc.get(HttpStorageRpc.java:433) ~[google-cloud-storage-1.79.0.jar:1.79.0]
at com.google.cloud.storage.StorageImpl$5.call(StorageImpl.java:240) ~[google-cloud-storage-1.79.0.jar:1.79.0]
at com.google.cloud.storage.StorageImpl$5.call(StorageImpl.java:237) ~[google-cloud-storage-1.79.0.jar:1.79.0]
at com.google.api.gax.retrying.DirectRetryingExecutor.submit(DirectRetryingExecutor.java:105) ~[gax-1.46.1.jar:1.46.1]
at com.google.cloud.RetryHelper.run(RetryHelper.java:76) ~[google-cloud-core-1.79.0.jar:1.79.0]
at com.google.cloud.RetryHelper.runWithRetries(RetryHelper.java:50) ~[google-cloud-core-1.79.0.jar:1.79.0]
at com.google.cloud.storage.StorageImpl.get(StorageImpl.java:236) ~[google-cloud-storage-1.79.0.jar:1.79.0]
at com.google.cloud.storage.StorageImpl.get(StorageImpl.java:254) ~[google-cloud-storage-1.79.0.jar:1.79.0]
at org.springframework.cloud.gcp.storage.GoogleStorageResource.getBlob(GoogleStorageResource.java:165) ~[spring-cloud-gcp-storage-1.1.2.RELEASE.jar:1.1.2.RELEASE]
at
Thank you Joe. The resource to implement 'Spring Cloud GCP Core' was never mentioned in the tutorials or i overlooked it.
Somehow another account was connected in my Google Cloud SDK on my console. So i used
gcloud auth application-default login
and logged in the right account. Now it works. Thank you.
This looks like an issue regarding authentication. Did you follow the generic 'Spring Cloud GCP Core' [1] configuration?
Check your application.properties [2] (or other configuration) and make sure it contains at least the following properties:
spring.cloud.gcp.datastore.project-id=XXX
spring.cloud.gcp.datastore.credentials.location=YYY
or choose an other method shown in [1].
[1] https://cloud.spring.io/spring-cloud-static/spring-cloud-gcp/1.1.2.RELEASE/single/spring-cloud-gcp.html#spring-cloud-gcp-core
[2] https://github.com/spring-cloud/spring-cloud-gcp/blob/master/spring-cloud-gcp-samples/spring-cloud-gcp-data-datastore-sample/src/main/resources/application.properties
I am having a issue related to authentication where I am getting logged out of my app when trying to GET from an endpoint that was created from a POST (HTTTP STATUS 201) I see the following errors. The backend is seeing the user as anonymousUser while I am logged in but works fine for another endpoint in the same file :
2018-10-22 11:33:35.251 DEBUG 2124 --- [ XNIO-8 task-23]
c.c.link.aop.logging.LoggingAspect : Enter:
org.springframework.boot.actuate.audit.AuditEventRepository.add() with
argument[s] = [AuditEvent [timestamp=Mon Oct 22 11:33:35 PDT 2018,
principal=anonymousUser, type=AUTHORIZATION_FAILURE,
data={details=org.springframework.security.web.authentication.WebAuthenticationDetails#fffed504:
RemoteIpAddress: 127.0.0.1; SessionId:
_5aP-S8x27gGSIjtbkR6EwrWOD9Yybnd-4M3z0ol, type=org.springframework.security.access.AccessDeniedException,
message=Access is denied}]] 2018-10-22 11:33:35.258 DEBUG 2124 --- [
XNIO-8 task-23] c.c.link.aop.logging.LoggingAspect : Exit:
org.springframework.boot.actuate.audit.AuditEventRepository.add() with
result = null 2018-10-22 11:33:35.343 WARN 2124 --- [ XNIO-8 task-23]
o.z.p.spring.web.advice.AdviceTrait : Unauthorized: Full
authentication is required to access this resource
The same resource (DeliveryResource.java) has an endpoint that works fine
the only difference between both end points is one is /getList (this one is working fine) VS. /getPackingListReport/{number} (this one fails authentication).
The API definitions are shown below:
#GetMapping("/getPackingListReport/{number}")
#Secured(AuthoritiesConstants.USER)
#Timed
public ArrayList<WebOrder> getPackingListReportFromDB(#PathVariable("number") long packingListNbr)
vs.
#GetMapping("/getList")
#Secured(AuthoritiesConstants.USER)
#Timed
public WebOrder getList(#RequestParam(value = "custid") long custid,#RequestParam(value = "pId") long pId) {
I found the problem.
I was using the following for the "/getList" mapping:
// call dao to insert to DB the list and then call the stored proc
URI location = ServletUriComponentsBuilder.fromCurrentContextPath().path("/api/rest/getPackingListReport/{packingListNumber}").buildAndExpand(packingListNumber).toUri();
return ResponseEntity.created(location).build();
to return a created resource URI (HTTP STATUS 201) after a POST. That path contained the incorrect URI starting with , "http://localhost" when jHipster is currently default set to only handle and look for "/api" or in my case i added "/rest/api/*" on the Angular5 side.
I fixed the issue by filtering out any characters before "/api/" after receiving the URL.
I triggered CAS Single Sign Out event by visit https://xx/cas-server/logout?service=myservice, and CAS POST a request to myservice(http://test.ogg:8080/cas) with the body:
<samlp:LogoutRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="LR-329-TxwPlscwOydLQH0JD0R2AKmOr4ew5FdiKN2" Version="2.0" IssueInstant="2016-07-15T08:21:38Z"><saml:NameID xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">#NOT_USED#</saml:NameID><samlp:SessionIndex>ST-329-lNWcDWJIW0Ve7ij9gsNG-cas</samlp:SessionIndex></samlp:LogoutRequest>
I have customised logout logic, so used the ticket in <samlp:SessionIndex>ST-329-lNWcDWJIW0Ve7ij9gsNG-cas</samlp:SessionIndex> to call https://xx/cas-server/validateService?service=myservice&ticket=ST-329-lNWcDWJIW0Ve7ij9gsNG-cas, but CAS report ticket invalid:
<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
<cas:authenticationFailure code='INVALID_TICKET'>
Ticket 'ST-329-lNWcDWJIW0Ve7ij9gsNG-cas' not recognized
</cas:authenticationFailure>
Here is the log from CAS server:
2016-07-15 08:21:38,334 DEBUG [org.jasig.cas.logout.SamlCompliantLogoutMessageCreator.create(SamlCompliantLogoutMessageCreator.java:53)] - Generated logout message: [<samlp:LogoutRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="LR-328-qwK2GgGVhRlRtu9QtebIoXIo30iwd4dWWwu" Version="2.0" IssueInstant="2016-07-15T08:21:38Z"><saml:NameID xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">#NOT_USED#</saml:NameID><samlp:SessionIndex>ST-329-lNWcDWJIW0Ve7ij9gsNG-cas</samlp:SessionIndex></samlp:LogoutRequest>]
2016-07-15 08:21:38,334 DEBUG [org.jasig.cas.logout.LogoutManagerImpl.performBackChannelLogout(LogoutManagerImpl.java:143)] - Sending logout request for: [http://test.ogg:8080/cas]
2016-07-15 08:21:38,334 DEBUG [org.jasig.cas.util.SimpleHttpClient$MessageSender.call(SimpleHttpClient.java:297)] - Attempting to access http://test.ogg:8080/cas
2016-07-15 08:21:38,371 DEBUG [org.jasig.cas.web.support.AbstractArgumentExtractor.extractService(AbstractArgumentExtractor.java:45)] - Extractor generated service for: http://test.ogg:8080/cas
2016-07-15 08:21:38,372 DEBUG [org.jasig.cas.ticket.registry.DefaultTicketRegistry.getTicket(DefaultTicketRegistry.java:80)] - Attempting to retrieve ticket [ST-329-lNWcDWJIW0Ve7ij9gsNG-cas]
2016-07-15 08:21:38,372 INFO [org.jasig.cas.CentralAuthenticationServiceImpl.validateServiceTicket(CentralAuthenticationServiceImpl.java:413)] - ServiceTicket [ST-329-lNWcDWJIW0Ve7ij9gsNG-cas] does not exist.
It seems the ticket was expired in 1 second?
When you have logged out, you have logged out. There is nothing further for you to do. Everything is gone. You can't validate something that is destroyed.
Faced spring integration java-dsl issue, I'm stuck. This is a code I have for my flow declaration:
#Bean
public IntegrationFlow orchestrationFlow() {
return IntegrationFlows.from(
Jms.messageDrivenChannelAdapter(queueConnectionFactory())
.destination(bookingQueue())
.outputChannel(bookingChannel()))
.<String, BookingRequest>transform(s -> {
Ticket t = new Gson().fromJson(s, Ticket.class);
return new BookingRequest()
.setMovieId(t.getMovie().getId())
.setRow(t.getSeat().getRow())
.setSeat(t.getSeat().getNumber())
.setScreenNumber(t.getScreenNumber()
);
})
// HTTP part goes here
.<BookingRequest, HttpEntity>transform(HttpEntity::new)
.handle(
Http.outboundChannelAdapter(bookingServerUrl)
.httpMethod(HttpMethod.POST)
.extractPayload(true)
.expectedResponseType(BookStatus.class)
)
// and here HTTP part ends
.handle(
Jms.outboundAdapter(responseDestinationTemplate())
)
.get();
}
And everything was OK until I utilized HTTP outbound channel adapter. I need to call simple RESTful interface and code above does it pretty well. But, following Jms.outboundAdapter(responseDestinationTemplate()) line leads to nothing, no action performes after successfull http call.
If I remove http flow part (surrounded by comments) - it works. Implemented so much stuff, almost understood and saw beauty and simplicity of integration ...aand this is it. Yet another place I got stuck in.
And here are log after success REST call:
2016-02-08 21:01:22.155 DEBUG 18209 --- [enerContainer-1] o.s.web.client.RestTemplate : POST request for "http://localhost:9052/api/book" resulted in 200 (OK)
2016-02-08 21:01:22.156 DEBUG 18209 --- [enerContainer-1] o.s.web.client.RestTemplate : Reading [class c.e.m.integration.domain.BookStatus] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter#6b9469bd]
2016-02-08 21:01:22.168 DEBUG 18209 --- [enerContainer-1] i.h.o.HttpRequestExecutingMessageHandler : handler 'org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler#0' produced no reply for request Message: GenericMessage [payload=<BookingRequest(movieId=0, row=1, seat=1, screenNumber=1),{}>, headers={jms_redelivered=false, jms_replyTo=queue://statusChannel, jms_correlationId=5021291a-d4d5-47ca-b591-b6f311378688, correlationId=1d41f05a-3695-4adb-87b0-d75c17bbc3ad, id=a1fb2a2f-5d78-3183-d409-3f60aae74a20, priority=4, jms_timestamp=1454950877264, jms_messageId=ID:ins-laptop-31198-1454948247657-1:9:1:1:1, timestamp=1454950877352}]
2016-02-08 21:01:22.168 DEBUG 18209 --- [enerContainer-1] o.s.integration.channel.DirectChannel : postSend (sent=true) on channel 'inboundFlow.channel#2', message: GenericMessage [payload=<BookingRequest(movieId=0, row=1, seat=1, screenNumber=1),{}>, headers={jms_redelivered=false, jms_replyTo=queue://statusChannel, jms_correlationId=5021291a-d4d5-47ca-b591-b6f311378688, correlationId=1d41f05a-3695-4adb-87b0-d75c17bbc3ad, id=a1fb2a2f-5d78-3183-d409-3f60aae74a20, priority=4, jms_timestamp=1454950877264, jms_messageId=ID:ins-laptop-31198-1454948247657-1:9:1:1:1, timestamp=1454950877352}]
2016-02-08 21:01:22.168 DEBUG 18209 --- [enerContainer-1] o.s.integration.channel.DirectChannel : postSend (sent=true) on channel 'inboundFlow.channel#1', message: GenericMessage [payload=BookingRequest(movieId=0, row=1, seat=1, screenNumber=1), headers={jms_redelivered=false, jms_replyTo=queue://statusChannel, jms_correlationId=5021291a-d4d5-47ca-b591-b6f311378688, correlationId=1d41f05a-3695-4adb-87b0-d75c17bbc3ad, id=859af23d-214f-4400-e9cb-7d40308755cd, priority=4, jms_timestamp=1454950877264, jms_messageId=ID:ins-laptop-31198-1454948247657-1:9:1:1:1, timestamp=1454950877350}]
2016-02-08 21:01:22.168 DEBUG 18209 --- [enerContainer-1] o.s.integration.channel.DirectChannel : postSend (sent=true) on channel 'inboundFlow.channel#0', message: GenericMessage [payload={"screenNumber":1,"seat":{"row":1,"number":1},"movie":{"id":0,"name":"The Matrix"}}, headers={jms_redelivered=false, jms_replyTo=queue://statusChannel, jms_correlationId=5021291a-d4d5-47ca-b591-b6f311378688, correlationId=1d41f05a-3695-4adb-87b0-d75c17bbc3ad, id=636638ed-aec2-082e-6181-0484999fd807, priority=4, jms_timestamp=1454950877264, jms_messageId=ID:ins-laptop-31198-1454948247657-1:9:1:1:1, timestamp=1454950877331}]
No errors, no warnings at all.
Spring Integration provides two MessageHandler types: one-way - just handle message and stop. And another one is like: handle request message and produce reply to the output channel.
The first one is called like outboundChannelAdapter and with your HTTP case you just only send a POST request and don't worry about the reply.
Since the message flow is stopped on the outboundChannelAdapter no any further action is possible in the integration chain. Like in your case the next Jms.outboundAdapter won't be reached.
If you really expect the reply from your REST service you should use Http.outboundGateway instead. And your BookStatus will be sent to the JMS as you'd like by your last .handle() in the flow.