403 Forbidden: "An expected CSRF token cannot be found" - csrf

I setup a springboot admin and client accoding to https://codecentric.github.io/spring-boot-admin/2.5.6/#securing-spring-boot-admin.
The admin server is ok,but when I run springboot client , there is a error for CSRS.
How can I resolve the issue.
2023-01-30 13:58:08.387 WARN 24920 --- [gistrationTask1]
d.c.b.a.c.r.ApplicationRegistrator : Failed to register
application as Application(name=client,
managementUrl=http://192.168.111.1:9222/actuator,
healthUrl=http://192.168.111.1:9222/actuator/health,
serviceUrl=http://192.168.111.1:9222/) at spring-boot-admin
([http://localhost:9111/instances]): 403 Forbidden: "An expected CSRF
token cannot be found". Further attempts are logged on DEBUG level
springboot client includes
config file:
#Configuration
public class SecurityPermitAllConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().permitAll()
.and().csrf().disable();
}
}
yml file:
server:
port: 9222
spring:
application:
name: client
boot:
admin:
client: # spring-boot-admin 客户端配置
url: http://localhost:9111 #服务端连接地址
username: admin # 服务端账号
password: admin # 服务端密码
instance:
prefer-ip: true # 使用ip注册
# 服务端点详细监控信息
management:
# health: # 检测服务状态是通过http://localhost:9111/actuator/health接口,可去掉不用检测项
# mail: # 健康检测时,不要检测邮件
# enabled: false
trace:
http:
enabled: true
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: always
logfile: # 日志(想在线看日志才配)
external-file: ./logs/client-info.log # 日志所在路径
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--Spring Boot Admin Server监控服务端-->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>2.5.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>

I got it.
My admin server's pom dependency use javax.servlet instead of spring-boot-starter-web

Related

Keycloak OIDC Filter redirect_uri is always http

My application was developed using wicket and integrated with keycloak 10.0.2.
I have an issue with the redirect_uri, it is always in http (like https://id.dev.subok.com/auth/realms/subok/protocol/openid-connect/auth? ... &redirect_uri=http%3A%2F%2Ftest.subok.com%2F ....
To elaborate:
When I try to access my app via https://test.subok.com, I am expecting that the redirect_uri will be https%3A%2F%2Ftest.subok.com%2F but it was http%3A%2F%2Ftest.subok.com%2F. The redirect_uri is always http even if I use http or https.
The way I integrate Keycloak to my application is via servlet filter:
POM
...
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-servlet-filter-adapter</artifactId>
<version>10.0.2</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-client</artifactId>
<version>10.0.2</version>
</dependency>
...
web.xml
...
<filter>
<filter-name>keycloak</filter-name>
<filter-class>org.keycloak.adapters.servlet.KeycloakOIDCFilter</filter-class>
<init-param>
<param-name>keycloak.config.skipPattern</param-name>
<param-value>/((error-page.html)|(access-denied-page.html))</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>keycloak</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
...
Is there a way to override the value of generated redirect_uri? Specifically to use https if the request is https and http if the request is http. Or just use https redirect_url for both http and https request?

Zuul reverse Proxy gives 404 when forwarding the request to services after upgrading to Greenwich release

I am using spring embedded Zuul proxy and eureka service registry in my microservice application.
After upgrading the spring cloud dependencies to Greenwich it gives 404 error in zuul gateway level.
Following are my configurations.
Zuul Gateway Main class
#SpringBootApplication
#EnableZuulProxy
#EnableSwagger2
#EnableHystrixDashboard
#EnableHystrix
public class GatewayApplication {
}
application.yml
zuul:
ignoreSecurityHeaders: false
sensitiveHeaders:
routes:
oauth:
path: /oauth/**
serviceId: oauth-server
payment:
path: /payment/**
serviceId: payment-service
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8082/eureka/
registerWithEureka: true
spring:
application:
name: zuul-gateway
Payment service main class
#SpringBootApplication()
#EnableJpaRepositories({ "com.payment.repo" })
#EntityScan("com.payment.domain")
#EnableEurekaClient
#EnableSwagger2
public class PaymentServiceApplication {}
application.yml
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8082/eureka/
registerWithEureka: true
spring:
application:
name: payment-service
I was able to forward requests successfully to services from zuul proxy with Finchley.RELEASE. Following are the previous maven dependencies.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
<relativePath/>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave-bom</artifactId>
<version>5.4.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
After upgrading spring cloud dependencies to Greenwich.release I'm unable to forward requests to services from zuul proxy. It's giving 404.
Because when call payment-service in zuul previously URL shows as
http://localhost:8181/payment/v1/fundTransfer/test
Now it shows as
http://localhost:8181/v1/fundTransfer/test
It seems zuul is not adding the path value (payment). If I revert back to Finchley It's working fine with same configurations.
Do I need to change any routing configuration in application.yml of zuul proxy?

Spring Cloud app - zuul timeout after deploying on Tomcat

I'm trying to set up a couple of services using Spring Cloud and everything seems to work fine up until the moment I deploy the Eureka client services to Tomcat. When I call a service through my gateway app, I get the following error:
o.s.c.n.z.filters.post.SendErrorFilter : Error during filtering
com.netflix.zuul.exception.ZuulException: Forwarding error
...
Caused by: com.netflix.hystrix.exception.HystrixRuntimeException: hello timed-out and no fallback available.
...
Caused by: java.util.concurrent.TimeoutException: null
It works perfectly from eclipse however. It even works when I run the discovery and gateway services from Tomcat, and run the Eureka client service from eclipse. But as soon as I run the same service on tomcat, I get the error.
I'm using Brixton.M5, Java 8 and Tomcat 8.
Again, the code seems to work, the problem is it doesn't work after being deployed to Tomcat.
I have one Tomcat instance for the Discovery and Gateway services, and a second Tomcat instance for the Eureka client services.
Here's some code and config..
DiscoveryServerApp
#SpringBootApplication
#EnableEurekaServer
public class DiscoveryServerApp extends SpringBootServletInitializer
{
public static void main(String[] args)
{
SpringApplication.run(DiscoveryServerApp.class, args);
}
}
DiscoveryServer - application.yml
# Configure this Discovery Server
eureka:
instance:
hostname: discovery
client: # Not a client, don't register with yourself
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://localhost:1111/discovery/eureka/
server:
port: 1111 # HTTP (Tomcat) port
context-path: /discovery
DiscoveryServer - bootstrap.yml
spring:
application:
name: discovery
jmx:
default-domain: com.example.cloud.discovery
GatewayApplication
#SpringCloudApplication
#EnableZuulProxy
public class GatewayApplication extends SpringBootServletInitializer
{
public static void main(String[] args)
{
SpringApplication.run(GatewayApplication.class, args);
}
}
GatewayApplication - application.yml
# Discovery Server Access
eureka:
client:
serviceUrl:
defaultZone: http://localhost:1111/discovery/eureka/
instance:
instanceId: ${spring.application.name}:${spring.application.instance_id:${random.value}}
# HTTP Server
server:
port: 4444 # HTTP (Tomcat) port
context-path: /api
GatewayApplication - bootstrap.yml
# Spring properties
spring:
application:
name: gateway-service # Identify this application
jmx:
default-domain: com.example.cloud.gateway
encrypt:
failOnError: false
DummyApplication
#SpringCloudApplication
#RestController
public class DummyApplication extends SpringBootServletInitializer
{
public static void main(String[] args)
{
SpringApplication.run(DummyApplication.class, args);
}
#RequestMapping( path = "/hello-resource", method = RequestMethod.GET )
public String hello()
{
return "hello";
}
}
DummyApplication - application.yml
# Discovery Server Access
eureka:
client:
serviceUrl:
defaultZone: http://localhost:1111/discovery/eureka/
instance:
instanceId: ${spring.application.name}:${spring.application.instance_id:${random.value}} # Unique id for multiple instances
# HTTP Server
server:
port: 3333 # HTTP (Tomcat) port
context-path: /hello-context
DummyApplication - bootstrap.yml
# Spring properties
spring:
application:
name: hello-service # Service registers under this name
jmx:
default-domain: com.example.cloud.hello
encrypt:
failOnError: false
I figured it out by accident... turns out that the value of server.port needs to match the port of the Tomcat instance where it's deployed. It seems obvious now, but I thought Spring would somehow magically figure that out from the container it's running in. I guess it would be a good idea to read that configuration from an external location to handle different environments without having to make 'code changes'.
So anyways, the answer is: make sure your server.port in application.yml matches the port on the target container.
Thanks to everyone who took the time to help me with this!
You should point your bowser to port 4444 (gateway), not 1111 (eureka).
Ok, #SpringCloudApplication wraps #EnableDiscoveryClient which causes DummyApplication to register itself with Eureka on startup. You can confirm this is happening through the Eureka dashboard.
Assuming DummyApplication registers with Eureka as service name "hello-service", then Zuul / Ribbon will create a route for that service name. Thus, your "/hello-resource" endpoint should be proxied through Zuul at:
http://localhost:4444/api/hello-service/hello-resource/

Eureka based configuration server breaking actuator endpoints

I setup my services to use the spring cloud eureka based config server.
version info: spring cloud 1.0.1.RELEASE
When I set it up as a fixed endpoint, I can see that it gets the right configuration file and that I can access actuator endpoints like health, info etc. so a .../manage/info returns the correct information.
However when I set it up to use discovery, the same actuator endpoints timeout on trying got access them.
In each case the configuration file is retrieved and downloaded (included log file).
Is there an issue with how I setup config server and bookmark service (the service which uses the config server)?
My configuration server setting is as follows:
server:
port: 8888
contextPath: /configurationservice
eureka:
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: http://localhost:8761/eureka/
instance:
leaseRenewalIntervalInSeconds: 10
statusPageUrlPath: /configurationservice/info
homePageUrlPath: /configurationservice/
healthCheckUrlPath: /configurationservice/health
preferIpAddress: true
spring:
cloud:
config:
server:
native:
searchLocations: file:/Users/larrymitchell/libertas/configserver/configfiles
The service bootstrap.yml settings are:
spring:
profiles:
default: development
active: development
application:
name: bookmarkservice
cloud:
config:
enabled: true # note this needs to be turned on if you wnat the config server to work
# uri: http://localhost:8888/configurationservice
label: 1.0.0
discovery:
enabled: true
serviceId: configurationservice
The application.yml settings are:
# general spring settings
spring:
application:
name: bookmarkservice
profiles:
default: development
active: development
# name of the service
service:
name: bookmarkservice
# embedded web server settings
# some of these are specific to tomcat
server:
port: 9001
# the context path is the part after http:/localhost:8080
contextPath: /bookmarkservice
tomcat:
basedir: target/tomcat
uri-encoding: UTF-8
management:
context-path: /manage
security:
enabled: false
eureka:
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: http://localhost:8761/eureka/
instance:
statusPageUrlPath: /bookmarkservice/manage/info
homePageUrlPath: /bookmarkservice/manage
healthCheckUrlPath: /bookmarkservice/manage/health
preferIpAddress: true
The startup log for bookmark service is as follows:
2015-06-24 17:52:49.806 DEBUG 11234 --- [ main] o.s.web.client.RestTemplate : Created GET request for "http://10.132.1.56:8888/configurationservice/bookmarkservice/development/1.0.0"
2015-06-24 17:52:49.890 DEBUG 11234 --- [ main] o.s.web.client.RestTemplate : Setting request Accept header to [application/json, application/*+json]
2015-06-24 17:52:50.439 DEBUG 11234 --- [ main] o.s.web.client.RestTemplate : GET request for "http://10.132.1.56:8888/configurationservice/bookmarkservice/development/1.0.0" resulted in 200 (OK)
2015-06-24 17:52:50.441 DEBUG 11234 --- [ main] o.s.web.client.RestTemplate : Reading [class org.springframework.cloud.config.environment.Environment] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter#2b07e607]
2015-06-24 17:52:50.466 INFO 11234 --- [ main] b.c.PropertySourceBootstrapConfiguration : Located property source: CompositePropertySource [name='configService', propertySources=[MapPropertySource [name='file:/Users/larrymitchell/libertas/configserver/configfiles/1.0.0/bookmarkservice-development.yml']]]
2015-06-24 17:52:50.503 INFO 11234 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext#5fa23965: startup date [Wed Jun 24 17:52:50 EDT 2015]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext#5cced717
2015-06-24 17:52:51.723 WARN 11234 --- [ main] .i.s.PathMatchingResourcePatternResolver : Skipping [/var/folders/kq/ykvl3t4n3l71p7s9ymywb4ym0000gn/T/spring-boot-libs/06f98804e83cf4a94380b46591b976b1d17c36b8-eureka-client-1.1.147.jar] because it does not denote a directory
2015-06-24 17:52:53.662 INFO 11234 --- [ main] o.s.b.f.config.PropertiesFactoryBean : Loading properties file from URL [jar:file:/Users/larrymitchell/libertas/vipaas/applicationservices/bookmarkservice/target/bookmarkservice.jar!/lib/spring-integration-core-4.1.2.RELEASE.jar!/META-INF/spring.integration.default.properties]
Ok, after talking it over with another coworker I figured out what the actual issue is.
Part of the confusion is that I am using the spring cloud (https://github.com/VanRoy/spring-cloud-dashboard) which is a great front end by the way. So when the service starts we see it for to discovery and retrieve the correct configuration file and load it. After I go to the spring cloud console and see a setting of UP which means that it is discovered and registered though discovery. There is a second status indicator which is when the spring cloud dashboard takes the registered endpoint and get health. In my issue the endpoint was showing up as UNKNOWN.
If I then use the endpoint that shows up in the console and try the info actuator endpoint then the request times out. This was the nature of my problem
Ok, so what was the issue?
Basically since I defined the in the application.yml and since when the service registers in bootstrap it does not know the port yet and then it picks a default of 8080 (my assumption since that is what it does). The server port is set in application.yml to 9001 but discovery sees a registration of 8080 so the spring cloud console cannot access the localhost:8080/bookmarkservice/manage/health since there is no service at that endpoint (which is at 9001 actually). Other services also cannot find the service.
By moving the server.port to bootstrap.yml then the correct endpoint of rate service is registered and the service properly accessible.

Working Java REST Client Example to access CAS REST API

I followed this tutorial to enable REST service on my local CAS server.
However there is no Java example
"Java REST Client Example
We need a real, working, example, the previous one is useless. Many people are emailing me that it is not working, and I confirm it does not work."
I was able to find this but that unfortunately did not work for me.
Any pointers/links? Much appreciated.
Got it!
Here is the complete solution on how to enable CAS REST API and be able to connect to it via JAVA REST client to benefit others
Get CAS source code.
Review this article
Add following to pom.xml like suggested by the article in #2
<dependency>
<groupId>org.jasig.cas</groupId>
<artifactId>cas-server-integration-restlet</artifactId>
<version>${cas.version}</version>
<type>jar</type>
</dependency>
Make sure to add following to pom.xml to avoid Spring jar collisions. In my case, cas-server-integration-restlet was dependent on spring-web, which used by default older version of Spring. So, I explicitly defined
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.1.1.RELEASE</version>
</dependency>
Compile your cas code. Should get cas.war in your target folder.
Upload it to your server, change permissions to tomcat and wait for it to get deployed
In CATALINA/conf find server.xml and uncomment 8443 port configuration so that our sever will allow SSL connections. Also, specify your certs in here.
Now navigate to exploded cas.war file and drill down to WEB-INF folder to find deployerConfigContext.xml file. Specify what CAS would use to authenticate. In my case, I used LDAP.
Add following to web.xml per article above
<servlet>
<servlet-name>restlet</servlet-name>
<servlet-class>com.noelios.restlet.ext.spring.RestletFrameworkServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>restlet</servlet-name>
<url-pattern>/v1/*</url-pattern>
</servlet-mapping>
Restart tomcat for changes to take effect.
Test that you can log in via standard CAS UI: https://server:8443/cas/login
Test that REST API was exposed via: https://server:8443/cas/v1/tickets
Now let's connect to it. I used this sample code. Make sure to give correct links and username/password
When I tried running the code as is, it complained about "Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target". Basically asking you to install certs. If you have the access to the server, just copy it over. If not, I found this code that will take care of the installation for you if you dont have access or just too lazy :)
Now, if you run the JAVA CAS Client with valid credentials you should see something like
201
https://server_name:8443/cas/v1/tickets/TGT-4-rhVWLapYuOYi4InSEcmfNcABzaLMCPJgGIzlKqU1vb50zxb6pp-server_name
Tgt is : TGT-4-rhVWLapYuOYi4InSEcmfNcABzaLMCPJgGIzlKqU1vb50zxb6pp-server_name.ndev.coic.mil
Service url is : service=https%3A%2F%2Fmyserver.com%2FtestApplication
https://server_name:8443/cas/v1/tickets/TGT-4-rhVWLapYuOYi4InSEcmfNcABzaLMCPJgGIzlKqU1vb50zxb6pp-server_name
Response code is: 200
200
ST-4-BZNVm9h6k3DAvSQe5I3C-server_name
You can see 200 code and the ticket. If you were to review logs of your cas on the server, you should see messages about successful athentication and ticket generation.
Change username/password to some dummy data and try to run the code. You will get 400 error message, which means that permission to access was denied.
Success!
For CAS 4.0 it's a little simpler (tested on apache-tomcat-7.0.55)
in your pom.xml add following dependency
<dependency>
<groupId>org.jasig.cas</groupId>
<artifactId>cas-server-integration-restlet</artifactId>
<version>4.0.0</version>
<scope>runtime</scope>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
</exclusions>
</dependency>
Direct dependency to springframework is not necesarry because exclusions prevent from duplicated packages
In your web.xml you need to add servlet mapping for restlet (mind package has changed from com.noelios.restlet... to org.restlet...
<servlet>
<servlet-name>restlet</servlet-name>
<servlet-class>org.restlet.ext.spring.RestletFrameworkServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>restlet</servlet-name>
<url-pattern>/v1/*</url-pattern>
</servlet-mapping>
As a result of above steps in yuor WEB-INF/lib directory following new files should be added
ls target/cas/WEB-INF/lib/ | grep restlet
cas-server-integration-restlet-4.0.0.jar
org.restlet-2.1.0.jar
org.restlet.ext.servlet-2.1.0.jar
org.restlet.ext.slf4j-2.1.0.jar
org.restlet.ext.spring-2.1.0.jar
If you wish to skip cert validation add this to your Java Client
//////////////////////////////////////////////////////////////////////////////////////
// this block of code turns off the certificate validation so the client can talk to an SSL
// server that uses a self-signed certificate
//
// !!!! WARNING make sure NOT to do this against a production site
//
// this block of code owes thanks to http://www.exampledepot.com/egs/javax.net.ssl/trustall.html
//
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType){}
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType){}
}
};
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
//
//
// end of block of code that turns off certificate validation
// ////////////////////////////////////////////////////////////////////////////////////
Usually devs are confused on how to get rest client working when accessing secured CAS web service. Most of the question out there were asking how to get restlet CAS secures a webservice and how to call those web service, because no real example were working.
Well actually there is. Groovy example is on the JASIG Cas restlet example https://wiki.jasig.org/display/casum/restful+api is clearly show how to get authenticated to call a service (its using Groovy, but converting to Java should be straight forward) . But in my opinion, it do not clearly explain that client need to authenticate to the designated web service first before accessing CAS secured web service.
For example, assume there is a JSON service that secured with CAS and build with Java and Spring. And you are using code that describe on the groovy section on https://wiki.jasig.org/display/casum/restful+api
String casUrl="https://yourcas.com/v1/tickets"
String springTicketValidation="http://yourservice.com/j_spring_cas_security_check"
String serviceToCall="http://yourservice.com/serviceToCall"
To get your service client be able to call the service, you need to follow these simple rules:
Get your ticket granting ticket from CAS
Get your Service Ticket from cas for the designated service call (service to call)
Authenticate to your service ticket validator (at this point url specified on springTicketValidation)
finally call your service
or in code perspective
String ticketGrantingTicket = getTicketGrantingTicket(casUrl, username, password)
String serviceTicket = client.getServiceTicket(casUrl, ticketGrantingTicket, serviceToCall)
// validate your ticket first to your application
getServiceCall(springTicketValidation, serviceTicket)
getServiceCall(serviceToCall, serviceTicket)
And for your note, all these operation should be done in following condition:
Your call (both restlet call and service call) should be done in the same HttpClient object. It seems that CAS put "something" in the session object that validated when you call your service. Fails this, and you will always get logon page on the HTTP result.
Your cas client should be able to recognized your CAS SSL certificate, otherwise it will throw you PKIX path building failed
This example is based on the cas secured web service that using Spring Security to secured service with CAS. I'm not sure whether other cas secured should need ticket validation on the application side or not
Hope this help