I am receiving a Request method 'POST' not supported error when I #EnableOAuth2Sso on my Spring Boot 1.5.9 / Angular 5 app.
GET requests work fine, and the JSESSIONID cookie looks like it's setting itself just fine on the front-end. Cookie is getting passed with all requests, and matches.
In the Response Header: Status Code: 405 Allow: GET, HEAD
This is my first Stack Overflow question, I've done all of my usual sleuthing and can't seem to get to the bottom of this one. I apologize in advance for any oversights in my asking / formatting of this question.
#SpringBootApplication
#EnableOAuth2Sso
#EnableOAuth2Client
public class CompanyApplication {
public static void main(String[] args) {
SpringApplication.run(CompanyApplication.class, args);
}
}
Relevant Controller
#RestController
#RequestMapping("api")
public class CompanyController {
#Autowired
CompanyRepository companyRepository;
#Autowired
ContactRepository contactRepository;
#PostMapping("companies")
public Company createCompany(#Valid #RequestBody Company company) {
logger.info("*** Starting POST request of company name: {}", company.getName());
company = updateContacts(company); // pass updated contact info into the Contact DB
companyRepository.save(company);
logger.info("*** Successful POST request of company: {}, ID: {},", company.getName(), company.getId());
return company;
}
Config settings:
security.oauth2.client.clientId=myID
security.oauth2.client.clientSecret=mySecret
security.oauth2.client.accessTokenUri=https://myserver.com/connect/token
security.oauth2.client.userAuthorizationUri=https://myserver.com/connect/authorize
security.oauth2.client.scope=openid,profile,email
security.oauth2.resource.userInfoUri=https://myserver.com/connect/userinfo
Angular service:
public updateCompany( companyData: Company ) {
return this.http.post(this.url, companyData);
}
Edit:
I followed the advice of #theLearner below, but still wanted to add CSRF (XSRF) protection. This is how I ended up doing it:
In app.module.ts add HttpClientXsrfModule to imports (I'm on Angular 5).
Remove #EnableOAuth2Sso from root CompanyApp class.
Config as follows:
#Configuration
#EnableOAuth2Sso
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.
authorizeRequests().anyRequest().authenticated().
and().
csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}
}
There are following things you need to do.
In application properties add this config:
security.oauth2.resource.filter-order=3
More info about this is here.
Since you have not posted your Spring security config yet, not sure how is it right now. But it should look like this:
#Configuration
#EnableOAuth2Sso
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable() // or replace this with tour csrf token repository
.authorizeRequests()
.anyRequest().authenticated();
}
This SO post explains if #EnableOauth2Sso is not used carefully it can really mess up entire security configuratiin
Related
I have a WebApp consisting of 2 parts.
One is with a frontend (Vaadin) where i want the user to be Logged-In via OAuth2. I then Check whether the user has a certain Role or not. --> If user opens the URL he shall be redirected to the OAuthLogin automatically. --> This is working with the #EnableOAuthSso.
Second Part is the REST-API of the Application, which is found by anything under /api/*. fE. /api/devices
should give me a list if the Get-Request has a valid Bearer-Token. If the GET Request has no Bearer-Token or a wrong Role (Authority) if want to get a 403.
Now this is my configuration:
#Configuration
#EnableOAuth2Sso
public class ProdWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
private static final String ADMIN_ROLE= "role.global.admin";
private static final String READ_API_ROLE= "role.base.read.api";
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests()
.antMatchers("/login**", "/error**").permitAll()
.antMatchers("/*").hasAuthority(ADMIN_ROLE)
.antMatchers("/api/**").hasAnyAuthority(ADMIN_ROLE, READ_API_ROLE)
.and().logout().permitAll().logoutSuccessUrl(rootAuthUri + "/connect/endsession")
;
}
Now when opening for example /manageDevices in the Browser i get forced to be logged in via Auth-Code-Flow and everything works like as expected.
When i try to open /api/devices i also get forced to be logged in via Oauth. Even when i do send Http-Header with Authentication: Bearer xxxxx. Somehow it always forces me to the Login-Screen from my OAuth login.
application.properties these lines are defined:
base.rootauthuri=https://oauth2.mypage.ch
security.oauth2.client.clientId=client.base.parameters
security.oauth2.client.clientSecret=secret
security.oauth2.client.accessTokenUri=${base.rootauthuri}/connect/token
security.oauth2.client.userAuthorizationUri=${base.rootauthuri}/connect/authorize
security.oauth2.client.scope=openid,scope.base.parameters,role,offline_access
security.oauth2.client.clientAuthenticationScheme=form
security.oauth2.resource.userInfoUri=${base.rootauthuri}/connect/userinfo
How can i force everything under /api/* to not redirect to the AuthenticationForm but respond with 403 if no Bearer Token is sent. How can i make it to Check whether the Bearer-Token has Role "READ_API_ROLE" also.
I had the same question with SSO, I configured a ResourceServe for that:
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Autowired
private ResourceServerConfiguration configuration;
#PostConstruct
public void setSecurityConfigurerOrder() {
configuration.setOrder(3);
}
#Bean("resourceServerRequestMatcher")
public RequestMatcher resources() {
return new AntPathRequestMatcher("/api/**");
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers("/v1/**") // this is free resource
.and().authorizeRequests()
.antMatchers("/api/**").permitAll() // This is free resource for mvc calls
// Usado para paths que necessitam de token bearer
.and().requestMatchers().antMatchers("/integration/**")
.and().authorizeRequests()
.antMatchers("/integration/**").authenticated(); // this is protected resource, it's necessary token
}
}
I not configure WebSecurityConfigurerAdapter in my project;
Check this:
Spring Boot 1.3.3 #EnableResourceServer and #EnableOAuth2Sso at the same time
https://www.baeldung.com/spring-security-oauth2-enable-resource-server-vs-enable-oauth2-sso
I am new to spring security and I am trying to build a restful API based sample Spring Security based example and I have used Spring Boot to create project.But I am getting following error when I send a request url:-
Request Url:-
http://localhost:8080/message
Response Got: -
{"timestamp":1505139451257,"status":401,"error":"Unauthorized","message":"Full authentication is required to access this resource","path":"/message"}
The Below is the code I have added:-
1] Main Class
#SpringBootApplication
#ComponentScan("com.srikss.controller")
public class SrikSsApplication {
public static void main(String[] args) {
SpringApplication.run(SrikSsApplication.class, args);
}
Controller:-
#RestController
public class HelloWorldController {
#RequestMapping(value="/message",method=RequestMethod.GET,headers="Accept=application/json")
public String messageLoad()
{
return "hello";
}
}
Configuration Class: -
#Configuration
#EnableWebSecurity
public class SrikSSConfiguration extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity httpsecurity) throws Exception
{
httpsecurity.authorizeRequests().anyRequest().permitAll().and()
.httpBasic();
httpsecurity.csrf().disable();
}
}
Can anyone help me to figure out what I am doing wrong here.
Thanks in advance.
Finally got the reason what I was doing wrong.
with the help of this reference link:-
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-security.html
actually spring boot defines default password which generated randomly and the default user name is "user".
After I update the password in application.properties file got the desired result,
security.user.password=aaa
I want to secure my vaadin application with keycloak and spring security. I try to use the "keycloak-spring-security-adapter".
My problem is that I want also unauthenticated users to use my application, but with less functionality - I do this with method security and checking which roles the current user has in the UI.
Can I configure the filter so that it ignores unauthenticated requests, but If the token is present uses it?
Thanks
Daniel
A working example of what you want can be found in the public-access branch of this github project. It does use Vaadin 8 though.
In essence, you can setup your application to be partially public, i.e. accessibly to unauthenticated user for certain parts and requires login for others, as follows:
#Configuration
#EnableWebSecurity
#EnableVaadinSharedSecurity
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true, proxyTargetClass = true)
public class SecurityConfiguration extends KeycloakWebSecurityConfigurerAdapter {
...
#Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().disable();
http.formLogin().disable();
http.csrf().disable();
http
.authorizeRequests()
.antMatchers("/vaadinServlet/UIDL/**").permitAll()
.antMatchers("/vaadinServlet/HEARTBEAT/**").permitAll()
.anyRequest().permitAll();
http
.logout()
.addLogoutHandler(keycloakLogoutHandler())
.logoutUrl("/sso/logout").permitAll()
.logoutSuccessUrl("/");
http
.addFilterBefore(keycloakPreAuthActionsFilter(), LogoutFilter.class)
.addFilterBefore(keycloakAuthenticationProcessingFilter(), BasicAuthenticationFilter.class);
http
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint());
http
.sessionManagement()
.sessionAuthenticationStrategy(sessionAuthenticationStrategy());
}
...
}
The line http.anyRequest().permitAll(); is the most important where you configure the filter to just allow all requests. You could still update this to only allow public access to certain urls.
You can then use spring security annotations on methods/views/components to configure your fine-grained access control. E.g:
#SpringComponent
#Secured("ROLE_ANONYMOUS")
public class LoginOperation implements Runnable {
#Override
public void run() {
// login logic
}
}
and
#Secured("ROLE_USER")
public class LogoutOperation implements Runnable {
#Override
public void run() {
// logout logic
}
}
I have a rest webservice configured as a spring boot application.
All my rest urls have a base path "/api/...".
I am also serving static content from my application.
I need to configure security ONLY for the web service i.e., URLs that start with "/api/..." but give the other static content w/o applying security.
I've only seen examples where we filter some url patterns via:
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/*");
}
but not otherwise ...
Use the antMatcher method of HttpSecurity class:
#Configuration
#EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/api/**");
// add security constraints for /api/... here
}
/* rest of config */
}
Instead of antMatcher, you can you regexMatcher wich can be a negation pattern
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().regexMatchers(XXXXX);
}
Answer to your last comment, if you are using latest spring framework and spring security then define below class and security config as per the config standards.
package org.springframework.security.samples.config;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
public class MessageSecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
}
Also, look at below URL if you still find it difficult to get started with spring security.
http://docs.spring.io/spring-security/site/docs/3.2.6.RELEASE/reference/htmlsingle/#hello-web-security-java-configuration
Swagger works! I can interact with http://localhost:8090/sdoc.jsp and everything is fine.
I add the following to pom.xml...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
I also add the following two files:
#Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String name = authentication.getName();
String password = authentication.getCredentials().toString();
if( !Authenticate.authenticate(name, password) )
return null;
List<GrantedAuthority> grantedAuths = new ArrayList<>();
grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
Authentication auth = new UsernamePasswordAuthenticationToken(name, password, grantedAuths);
return auth;
}
#Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
and
#Configuration
#EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeRequests()
.anyRequest().permitAll()
.antMatchers("/**").authenticated().and()
.formLogin().loginPage("/login").permitAll().and()
.httpBasic()
;
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(new CustomAuthenticationProvider());
}
}
At this point if I visit the same URL that was previously working I now instead get a response type of "text/plain" and instead of a pretty HTML looking browser I see source code.
If I revert the change and remove the two files from project and remove JAR file it works again.
How do I get Spring Security and Swagger to play nice? What am I doing wrong.
I suspect this is due to Spring-Security's effect on the content-type headers (http://docs.spring.io/spring-security/site/docs/3.2.0.CI-SNAPSHOT/reference/html/headers.html#headers-content-type-options).
From the docs -
Historically browsers, including Internet Explorer, would try to guess the content type of a request using content sniffing. This allowed browsers to improve the user experience by guessing the content type on resources that had not specified the content type. For example, if a browser encountered a JavaScript file that did not have the content type specified, it would be able to guess the content type and then execute it.
The problem with content sniffing is that this allowed malicious users to use polyglots (i.e. a file that is valid as multiple content types) to execute XSS attacks. For example, some sites may allow users to submit a valid postscript document to a website and view it. A malicious user might create a postscript document that is also a valid JavaScript file and execute a XSS attack with it.
Again, from the docs, in order to override the default -
#EnableWebSecurity
#Configuration
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
// ...
.headers()
.contentTypeOptions();
}
}
Wow, I figured it was something along these lines. Thanks so much
When I tried this and it started working
.headers()
.disable()
I narrowed the default contentTypeOptions down to..
.headers()
//.contentTypeOptions() // If this is uncommented it fails.
.xssProtection()
.cacheControl()
.httpStrictTransportSecurity()
.frameOptions()
.and()