I have created Apache CXF SOAP webservice in Spring Boot as per below config:
#Bean
public ServletRegistrationBean wsDispatcherServlet() {
return new ServletRegistrationBean(new CXFServlet(), "/service/*");
}
#Bean
public Endpoint pegaEndpoint() {
EndpointImpl endpoint = new EndpointImpl(springBus, "/service/");
endpoint.publish("ws");
return endpoint;
}
Now I want to use httpBasic authentication to call a web service, but at the same time I want the WSDL to be publicly accessible.
Is that possible to configure with Spring Security?
I have below code in Java Configuration class for security, but it doesnt really work -
the basic authentication is enforced on both web service calls and wsdl accessed by http://localhost:8080/service/ws?WSDL
Can Spring Security differentiate based on the URL param?
Or can I set a WSDL location to be different that the URL used to call the web service?
#Autowired
private void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().
antMatchers("/service/**").hasRole("USER").and().httpBasic().and().
csrf().disable();
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/service/ws?wsdl");
}
I ended up doing below. Apparently ant matchers dont recognize any URL parameters so I used regex one:
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().regexMatchers("/service/ws\\?WSDL");
}
Permit all on the wsdl should do it -
http
.authorizeRequests()
.antMatchers("/service/ws?wsdl").permitAll()
.antMatchers("/service/**").hasRole("USER").and().httpBasic().and().
csrf().disable();
Related
I need to add a basic auth in only one of my controller method
Other method don't have an auth, but still have a #PreAuthorize in order to check if the parameters are valid.
My issue is , httpbasic transform all the exception throwed by preAuthorize in 401 ( some should be 403, etc).
I have the feeling that all my endpoint are under a basic auth, not just the ones I have use #Secured
How can I avoid that?
My code:
#Controller
class MyController {
#Secured("BASIC_AUTHENTIFIED")
public void someMethodOnlyForAuthentified(){...}
#PreAuthorize("check(parameters)")
public void someMethodForEveryone(List<String> parameters){...}
}
And in my security config:
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser(login).password(password).roles("BASIC_AUTHENTIFIED");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.authorizeRequests().antMatchers("/**").permitAll()
.anyRequest().authenticated()
.and().httpBasic()
.and().csrf().disable();
}
I'd like to secure my app using Spring Security's Resource Server and Authorization Server included in my component.
The desired flow include using only client-credentials grant type and passing client_id together with client_secret as base64 header, what should return token for further requests after hitting oauth/token endpoint. I also include grant_type: client-credentials in POST request parameters
For now I am receiving error:
"Full authentication is required to access this resource".
The strange thing is despite my configuration Spring still generates random security password what can be seen in console log.
This is my first approach to Spring Security so maybe I've missed something?
Below is my configuration:
AuthorizationServerConfig:
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends
AuthorizationServerConfigurerAdapter {
#Override
public void configure(final AuthorizationServerSecurityConfigurer security) {
security
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient("some-client")
.authorizedGrantTypes("client-credentials")
.authorities("ROLE_CLIENT")
.scopes("read", "write", "trust")
.accessTokenValiditySeconds(3600)
.secret("somePass")
.refreshTokenValiditySeconds(24*3600);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
.tokenStore(tokenStore())
.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
}
#Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
}
ResourceServerConfig:
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(final HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/oauth/token", "/oauth/authorize", "/oauth/confirm_access").permitAll()
.antMatchers("/**").authenticated()
.and().httpBasic().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
}
I am using Spring Boot 2.0.1.RELEASE and Spring Security OAuth2 2.0.14.RELEASE.
As in my case, InMemoryTokenStore is used it will work with one instance, what is the best substitute for this if one wanted to create multiple instances of app?
When you are storing the users in memory, you are providing the passwords in plain text and then when you are trying to retrieve the encoder from the DelegatingPasswordEncoder to validate the password it can't find one.
You can try out the following changes so that you can override password encoding by adding {noop}
#Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient("some-client")
.authorizedGrantTypes("client-credentials")
.authorities("ROLE_CLIENT")
.scopes("read", "write", "trust")
.accessTokenValiditySeconds(3600)
.secret("{noop}somePass") //change here
.refreshTokenValiditySeconds(24*3600);
}
And also change your user in WebSecurityConfigurer doing the same for the password.
I have to integrate my system with third-party provider. This system is made with Spring and Angular.
Keep in mind that I need to create a custom login form instead redirecting to thirdy-party provider form like OAuth2.
He has created following endpoints:
Get token authentication
POST http://example.com/webapi/api/web/token
“username=972.344.780-00&password=123456&grant_type=password”
The response send me a token that I must use during all next requests.
Get user info
Authorization: Bearer V4SQRUucwbtxbt4lP2Ot_LpkpBUUAl5guvxAHXh7oJpyTCGcXVTT-yKbPrPDU9QII43RWt6zKcF5m0HAUSLSlrcyzOuJE7Bjgk48enIoawef5IyGhM_PUkMVmmdMg_1IdIb3Glipx88yZn3AWaneoWPIYI1yqZ9fYaxA-_QGP17Q-H2NZWCn2lfF57aHz8evrRXNt_tpOj_nPwwF5r86crEFoDTewmYhVREMQQjxo80
GET http://example.com/webapi/api/web/userInfo
That said, What I need to implement a custom authentication?
Could I use Spring OAuth2 in this case?
you can use Spring Security. The flow is the following. You authenticate against the Security token service. A cookie containing the authentication token is written to your browser. This token is sent on each subsequent request against the server.
On the rest server you will use Srping Security and more specifily you need to use AbstractPreAuthenticatedProcessingFilter in its implementation you will extract the token and associate it With the Security Context.
Here is example configuration of your spring Security
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
// TODO Auto-generated method stub
return super.authenticationManagerBean();
}
public void configure(WebSecurity web) throws Exception {
// do some configuration here
}
#Override
public void configure(HttpSecurity http) throws Exception {
// configure your Security here
// you can add your implementation of AbstractPreAuthenticatedProcessingFilter here
}
}
Here is your additional configuration
#Configuration
public class ExampleSpringSecurityConfig{
#Bean
public AuthenticationManager authenticationManager() {
return authentication -> authProvider().authenticate(authentication);
}
private AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> userdetailsService() {
// Construct your AuthenticationUserDetailsService here
}
#Bean
public PreAuthenticatedAuthenticationProvider authProvider() {
PreAuthenticatedAuthenticationProvider authProvider = new PreAuthenticatedAuthenticationProvider();
authProvider.setPreAuthenticatedUserDetailsService(userdetailsService());
return authProvider;
}
}
Yes, you can use Spring Oauth2. You have to implement the Resource Owner Password Credentials Grant Oauth2 flow.
You have to create a login page for end user and your client app will send the user's credentials as well as your client system credentials (use HTTP Basic Authentication for client system credentials) to authorization server to get the token.
There are two ways to implement it-
Using client system id and password - When calling the token endpoint using the this grant type, you need to pass in the client ID and secret (using basic auth).
curl -u 972.344.780-00:123456 "http://example.com/webapi/api/web/token?grant_type=password&username=addEndUserNameHere&password=addEndUserPasswordHere"
Using Client system ID only (no client system password) - Authorization Server should have a client setup to support this flow without any password-
Child class of AuthorizationServerConfigurerAdapter should have below code-
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("clientId")
.authorizedGrantTypes("password")
.authorities("ROLE_CLIENT")
.scopes("read");
}
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.allowFormAuthenticationForClients();
}
Now you can use below-
POST http://example.com/webapi/api/web/token?grant_type=password&client_id=my-trusted-client&scope=trust&username=addEndUserNameHere&password=addEndUserPasswordHere
Note - This flow is less secure than other Oauth2 flows and recommended for trusted client app only because user has to provide credentials to client app.
See here example
Using JWT with Spring Security OAuth2 with Angular
In this tutorial, we’ll discuss how to get our Spring Security OAuth2 implementation to make use of JSON Web Tokens.
http://www.baeldung.com/spring-security-oauth-jwt
#Configuration
#EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore())
.accessTokenConverter(accessTokenConverter())
.authenticationManager(authenticationManager);
}
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("123");
return converter;
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
return defaultTokenServices;
}
}
I have a set a custom authentication filter in my Spring 4 MVC + Security + Boot project. The filter does it's job well and now I want to disable the security for some URI (like /api/**). Here is my configuration:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
#Override
public void configure(WebSecurity webSecurity) throws Exception {
webSecurity.ignoring().antMatchers("/api/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.addFilterBefore(filter, BasicAuthenticationFilter.class);
}
}
Unfortunately, when I call a resource under /api/... the filter is still chained. I've added println in my filter and it's written to the console on every call. Do you know what's wrong with my configuration?
UPDATE
Filter code:
#Component
public class EAccessAuthenticationFilter extends RequestHeaderAuthenticationFilter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("FILTER");
if(SecurityContextHolder.getContext().getAuthentication() == null){
//Do my authentication stuff
PreAuthenticatedAuthenticationToken authentication = new PreAuthenticatedAuthenticationToken(user, credential, authorities);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
super.doFilter(request, response, chain);
}
#Override
#Autowired
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
super.setAuthenticationManager(authenticationManager);
}
}
remove #Component on class EAccessAuthenticationFilter,and like this:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.addFilterBefore(new EAccessAuthenticationFilter(), BasicAuthenticationFilter.class);
}
https://github.com/spring-projects/spring-security/issues/3958
I don't have enough reputation to add a comment, but for anyone like me who was looking for a little more of an explanation for kimhom's answer, WebSecurityConfigurerAdapter will tell Spring Security to ignore any filters added through it. The filter was then still being invoked because the #Component (or any flavor of #Bean) annotation told Spring to add the filter (again) outside of the security chain. So while the filter was being ignored in the security chain, it was not being ignored by the other (non-security?) chain.
This solved two weeks of headaches for me. In my case my custom filter needed the Authentication object given by the SecurityContext where it kept coming up as null because the security chain was never executed.
I had the correct configuration to ignore some context path in the web security configuration as below..
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/v1/api1").antMatchers("/v1/api2");
}
But I mistakenly had added #PreAuthorize(...) on my controller method and it seems like that method level security was overriding any security configuration set up at the start.
After few tests I realized that in fact my configurations are ok and it's just a comprehension problem. The spring.security.ignored=/api/** doesn't bypass or turn off the filter. In reality every request still pass through my custom filter, but the difference is that Spring Security doesn't mind of the authentication status nor the granted authority coming from the custom filter.
I was wondering that the "ignored" property simply bypass the spring security filters. It sounds like I was totally wrong...
I always found the easiest way to do this is to put this configuration in your application.properties:
security.ignored=/api/**
I think you also need it in the Filter class as well (extends RequestHeaderAuthenticationFilter) i.e.
public class EAccessAuthenticationFilter extends RequestHeaderAuthenticationFilter {
public EAccessAuthenticationFilter() {
super(new RequestMatcher() {
RequestMatcher matcher = new AntPathRequestMatcher("/v1/api1");
return matcher.matches(request);
});
}
}
I have rest service with java back-end. i use Spring Security. What steps do I need to do in order to make authorization available to Android apps?
At the moment all works in the web version. This is Spring Security config.
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
AuthenticationService authenticationService;
#Override
protected void configure(HttpSecurity http) throws Exception {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
filter.setForceEncoding(true);
// отключена защита csrf на время тестов
http.csrf().disable().addFilterBefore(filter,CsrfFilter.class);
http.authorizeRequests().antMatchers("/account/**").hasRole("USER")
.antMatchers("/user/**").hasRole("ADMIN")
.and().formLogin();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(authenticationService);
}
P.S. Or any steps to do and no matter who acts as the client.
(i can authonticate via postman) I'm interested in the approach, whether it is necessary separately to implement in order to log in via the Android app was possible?