I need to implement CSRF protection to my backend. I am using the below configurations. But applications allow Post and Get requests without CSRF token.
#Slf4j
#EnableWebFluxSecurity
#EnableReactiveMethodSecurity
public class SecurityConfig {
#Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http
.csrf(csrf -> csrf.csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse()))
.authorizeExchange()
.anyExchange().authenticated()
.and().oauth2ResourceServer().jwt();
return http.build();
}
}
include the actual CSRF token in the HTTP request
#ControllerAdvice
public class SecurityControllerAdvice {
#ModelAttribute
Mono<CsrfToken> csrfToken(ServerWebExchange exchange) {
Mono<CsrfToken> csrfToken = exchange.getAttribute(CsrfToken.class.getName());
return csrfToken.doOnSuccess(token -> {
exchange.getAttributes()
.put(CsrfRequestDataValueProcessor.DEFAULT_CSRF_ATTR_NAME, token);
});
}
}
I tried the API using postman. But this is not working for me.
Spring version
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.3</version>
<relativePath/>
</parent>
Dependencies:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-resource-server</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
Final target: My frontend is Vuejs + nuxtjs. Can someone help me to
find the best way for implement this?
By using the oauth2ResourceServer() DSL, you are telling Spring Security that you are not using cookie-based authentication, therefore you do not need CSRF protection.
If you take a look at the OAuth2ResourceServerConfigurer#registerDefaultCsrfOverride you will notice that it doesn't apply the CSRF token validation to requests that contain a Bearer token, by using the BearerTokenRequestMatcher.
private void registerDefaultCsrfOverride(H http) {
CsrfConfigurer<H> csrf = http.getConfigurer(CsrfConfigurer.class);
if (csrf != null) {
csrf.ignoringRequestMatchers(this.requestMatcher);
}
}
CSRF exploits the browser behavior that automatically attaches the Cookies for the request, so I can trick users from my website www.malicioussite.example to click on a button and send a request to www.fakebank.example/transferMoneyToMe.
When you are using the Authorization header to send the JWT, the browser does not know about the access token, and therefore, will not attach the header automatically.
You can dive more deeply into this behavior starting from this answer https://security.stackexchange.com/questions/189326/do-i-need-csrf-protection-in-this-setup-with-a-rest-api-backed-with-oauth2-and-a
Related
Im trying to run Webflux on Tomcat and try to create Sping WebClient with Apache Http Client.
Reference Documentation stated that theres built-in support:
https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-client-builder-http-components
private ClientHttpConnector getApacheHttpClient(){
HttpAsyncClientBuilder clientBuilder = HttpAsyncClients.custom();
clientBuilder.setDefaultRequestConfig(RequestConfig.DEFAULT);
CloseableHttpAsyncClient client = clientBuilder.build();
ClientHttpConnector connector = new HttpComponentsClientHttpConnector(client);
return connector;
}
But Springs HttpComponentsClientHttpConnector is not accepting org.apache.http.impl.nio.client.CloseableHttpAsyncClient. It requires org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient. So there seems to be a package rename and I canĀ“t find a Maven Dependency that has the required class.
Does anybody know the right Maven Dependency for that class. Or how could I make it work?
Apache HTTP Client 5 is a separate artifact. You'll need to add the following dependencies to your pom.xml:
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.core5</groupId>
<artifactId>httpcore5-reactive</artifactId>
<version>5.1</version>
</dependency>
import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
import org.springframework.http.client.reactive.HttpComponentsClientHttpConnector;
public class ApacheHttp {
public static void main(String[] args) {
new HttpComponentsClientHttpConnector(HttpAsyncClients.custom().build())
}
}
I defined a pipeline in Apache Beam to consume messages of a given queue in RabbitMQ message broker.
I defined an exchange and routing key in RabbitMQ.
I used AmqpIO.read() in Beam (version 2.9.0) but I did not found any API to set the echange and the routing key.
(Following this doc : https://beam.apache.org/releases/javadoc/2.4.0/org/apache/beam/sdk/io/amqp/AmqpIO.html)
Is there any possibility to do that ? Even with any other plugin.
Regards,
Ali
There is a new (experimental) IO connector for RabbitMQ shipped with the latest v2.9.0 Apache Beam release. The AMQP connector will not work for RabbitMQ.
If you are using Maven add the following dependency in your POM
<!-- Beam MongoDB I/O -->
<dependency>
<groupId>org.apache.beam</groupId>
<artifactId>beam-sdks-java-io-mongodb</artifactId>
<version>2.9.0</version>
</dependency>
and you can use it in a pipeline like
public class RabbitMQPipeline {
final static Logger log = LoggerFactory.getLogger(RabbitMQPipeline.class);
/**
* Mongo Pipeline options.
*/
public interface RabbitMQPipelineOptions extends PipelineOptions {
#Description("Path of the file to read from")
#Default.String("amqp://localhost")
#Required
String getUri();
void setUri(String uri);
}
/**
* #param args
*/
public static void main(String[] args) {
RabbitMQPipelineOptions options = PipelineOptionsFactory.fromArgs(args).withValidation()
.as(RabbitMQPipelineOptions.class);
Pipeline pipeline = Pipeline.create(options);
PCollection<RabbitMqMessage> messages = pipeline
.apply(RabbitMqIO2.read().withUri(options.getUri()).withQueue("test"));
messages.apply(ParDo.of(new DoFn<RabbitMqMessage, String>() {
#ProcessElement
public void process(#Element RabbitMqMessage msg) {
System.out.println(msg.toString());
}
}));
pipeline.run().waitUntilFinish();
}
}
The RabbitMqIO Javadoc has examples of how to use the reader and writer.
A word of caution
There is a known bug that has been fixed but scheduled for release in v2.11.0 that blocks the connector from working even in the simplest scenarios. The fix is really simple (see JIRA issue) but you will need to rebuild a new version of the class. In case you want to give it a try make sure you add the following Maven dependency
<dependency>
<groupId>com.google.auto.value</groupId>
<artifactId>auto-value</artifactId>
<version>1.5.2</version>
<scope>provided</scope>
</dependency>
and add the following configuration in Maven Compiler plugin
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<annotationProcessors>
<annotationProcessor>com.google.auto.value.processor.AutoValueProcessor</annotationProcessor>
</annotationProcessors>
</configuration>
</plugin>
If you are using Eclipse make sure you install the m2-apt Maven plugin. Good luck!
I'm creating a Simple Selenium Cucumber project and defined steps using "Lambda Expressions Constructor" way for a feature file but when I ran the CucumberTest class I'm getting failure exception as
There are undefined steps!
My StepDefinition is below one
And Feature file is the below one
CucumberRunner class is below:
So please suggest me is there any different approach for calling Step Definition File if I use Lambda Expressions?
As already mentioned in my comment. The option glue expects a list of package names, not directories. Changing it from
glue = {"src/test/java/my.project.automation.wolfram_alpha" }
to
glue = {"my.project.automation.wolfram_alpha" }
will solve the issue.
Find working snippets below. Assuming following structure
src/test/java/my/project/automation/wolfram_alpha/StepDef.java
src/test/java/my/project/automation/wolfram_alpha/cucumberTest.java
src/test/resources/wolfram.feature
pom.xml
pom.xml (dependencies part)
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<version.cucumber>3.0.2</version.cucumber>
</properties>
<dependencies>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java8</artifactId>
<version>${version.cucumber}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>${version.cucumber}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-testng</artifactId>
<version>${version.cucumber}</version>
<scope>test</scope>
</dependency>
</dependencies>
cucumberTest.java
package my.project.automation.wolfram_alpha;
import cucumber.api.CucumberOptions;
import cucumber.api.testng.AbstractTestNGCucumberTests;
#CucumberOptions(
features = { "src/test/resources/wolfram.feature" },
glue = {"my.project.automation.wolfram_alpha" }
)
public class cucumberTest extends AbstractTestNGCucumberTests {
}
StepDef.java
package my.project.automation.wolfram_alpha;
import cucumber.api.java8.En;
public class StepDef implements En {
public StepDef() {
Given("URL of WolframAlpha" , () -> {
System.out.println("Given URL of WolframAlpha");
});
When("user logged in as {string} with {string}" , (String user, String password) -> {
System.out.printf("When user logged in as {%s} with {%s}%n", user, password);
});
And("login is successful" , () -> {
System.out.println("And login is successful");
});
And("user search for a {string}" , (String topic) -> {
System.out.printf("And user search for a {%s}%n", topic);
});
Then("results are displayed in a creative way" , () -> {
System.out.println("Then results are displayed in a creative way");
});
}
}
wolfram.feature from the question
Running the test with mvn test produces following output.
Running my.project.automation.wolfram_alpha.cucumberTest
Configuring TestNG with: org.apache.maven.surefire.testng.conf.TestNG652Configurator#726f3b58
Given URL of WolframAlpha
When user logged in as {user} with {password}
And login is successful
And user search for a {IDOL}
Then results are displayed in a creative way
1 Scenarios (1 passed)
5 Steps (5 passed)
I'm having problems defining configuration for a CDI application (glassfish 4).
I have:
#CacheResult(cacheName = "example")
public String getSomething(String something){
logger.debug("getSomething "+something);
return "this is "+something;
}
This works as expected, the second time is called is not executed because it's cached
However, I want to specify a configuration for my caches. I have tried writing a infinispan.xml file (in src/main/resources), but it's ignored. I have also tried with both:
#Produces
#Default
public Configuration defaultEmbeddedCacheConfiguration() {
return new ConfigurationBuilder().expiration().lifespan(3000l)
.eviction()
.strategy(EvictionStrategy.LRU)
.maxEntries(2)
.build();
}
#Produces
#ApplicationScoped
public EmbeddedCacheManager defaultEmbeddedCacheManager() {
return new DefaultCacheManager(defaultEmbeddedCacheConfiguration());
}
But these methods are never called.
I have also tried with #ConfigureCache
My dependencies are:
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-cdi</artifactId>
<version>6.0.2.Final</version>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-jcache</artifactId>
<version>6.0.2.Final</version>
</dependency>
Any ideas?
Thx
The upgrade request for opening a websocket connection is a standard HTTP request. On the server side, I can authenticate the request like any other. In my case, I would like to use Bearer authentication. Unfortunately, there is no way to specify headers when opening a websocket connection in the browser, which would lead me to believe that it's impossible to use bearer authentication to authenticate a web socket upgrade request. So -- Am I missing something, or is it really impossible? If it is impossible, is this by design, or is this a blatant oversight in the browser implementation of the websocket API?
The API allows you to set exactly one header, namely Sec-WebSocket-Protocol, i.e. the application specific subprotocol. You could use this header for passing the bearer token. For example:
new WebSocket("ws://www.example.com/socketserver", ["access_token", "3gn11Ft0Me8lkqqW2/5uFQ="]);
The server is expected to accept one of the protocols, so for the example above, you can just validate the token and respond with header Sec-WebSocket-Protocol=access_token.
You are right, it is impossible for now to use Authentication header, because of the design of Javascript WebSocket API.
More information can be found in this thread:
HTTP headers in Websockets client API
However, Bearer authentication type allows a request parameter named "access_token": http://self-issued.info/docs/draft-ietf-oauth-v2-bearer.html#query-param
This method is compatible with websocket connection.
Example for basic authentication using token servlet http request header before websocket connection:
****ws://localhost:8081/remoteservice/id?access_token=tokenValue****
verify your token return true if valid else return false
endpoint configuration:
#Configuration
#EnableWebSocket
public class WebSocketConfiguration implements WebSocketConfigurer{
#Autowired
RemoteServiceHandler rsHandler;
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry){
registry.addHandler(rsHandler, "/remoteservice/{vin}").setAllowedOrigins("*").addInterceptors(new HttpHandshakeInterceptor());
}
}
validate the token before established websocket connectin:
public class HttpHandshakeInterceptor implements HandshakeInterceptor{
#Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map attributes) throws Exception
{
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
String token = servletRequest.getServletRequest().getHeader("access_token");
try {
Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
if (claims!=null) {
return true;
}
} catch (Exception e) {
return false;
}
return false;
}
skip the http security endpoint
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().anyRequest();
}
}
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
add the request header in js file as you like
var request = URLRequest(url: URL(string: "ws://localhost:8081/remoteservice")!)
request.timeoutInterval = 5 // Sets the timeout for the connection
request.setValue("someother protocols", forHTTPHeaderField: "Sec-WebSocket-Protocol")
request.setValue("14", forHTTPHeaderField: "Sec-WebSocket-Version")
request.setValue("chat,superchat", forHTTPHeaderField: "Sec-WebSocket-Protocol")
request.setValue("Everything is Awesome!", forHTTPHeaderField: "My-Awesome-Header")
let socket = WebSocket(request: request)