Le problème :
Dans deux cas, j'exécute la commande mount via ansible pour monter un partage samba sur deux clients Linux.
Dans les deux cas, le montage est en échec pour cause :
- soit "CIFS VFS: validate protocol negotiate failed: -13"
- soit "CIFS VFS: BAD_NETWORK_NAME"
Solution :
Les erreurs venaient à chaque fois de ma configuration Samba côté serveur.
Les tests que j'ai réalisé pour retrouver la cause :
- Tester le montage du partage à partir de Windows (j'obtenais la même erreur : le problème vient du serveur)
- A partir des linux : smbclient -L <monserveur> -A /path/to/mycredentials
- ça, ça marchait dans 1 cas, dans l'autre cas, le nom du partage était mauvais : tilt ! (n°1)
- Avec le user samba, je suis aller dans le répertoire partagé pour vérifier que j'avais bien les droits
- et là ça ne marchait pas pour le 2ème cas (negociation failed)
Après avoir remis les droits pour l'un, corrigé mon template ansible pour l'autre, tout marche.
Pour info la configuration mis en place :
[global]
workgroup = SAMBA
security = user
unix password sync = no
log file = /var/log/samba/log.%m
guest account = {{samba_user.user}}
force group = {{samba_user.group}}
force user = {{samba_user.user}}
create mode = 0660
directory mode = 0770
[myshare]
path={{samba_share.export_path}}
public=yes
valid users={{samba_user.user}}
writable=yes
browseable = yes
force create mode = 0660
force directory mode = 0770
Et pour autoriser les users à se connecter via leur compte unix et toujours autoriser ce user générique à accéder aux fichiers :
# Ensure all files are owned by {{ samba_user.user }}
shell: "chown -R {{ samba_user.user }}:{{ samba_user.group }} {{samba_share.export_path}}"
# Ensure sticky bit is present on all directories
shell: "find {{ samba_share.export_path }} -type d -exec chmod g+s {} +"
# Add default rw for default group on {{ samba_share.export_path }}
shell: "setfacl -m d:g::rwx {{ samba_share.export_path }}"
# Add default rw for default group on subdirectories
shell: "find {{ samba_share.export_path }} -type d -exec setfacl -m d:g::rwx {} +"
Merci à eux :
https://superuser.com/questions/381416/how-do-i-force-group-and-permissions-for-created-files-inside-a-specific-directo
https://lea-linux.org/documentations/Gestion_des_ACL
Problem :
I used robertdebock/ansible-role-tomcat to install a Tomcat instance using Ansible. Works well until I deploy an application on it. Then java process hangs with 100% system CPU.
Starting with tomcat users without system work correctly.
Solution :
I suspected :
- SELinux
- Linux limits
- VM slow I/O
But after a while I ran strace :
- by modifying systemd configuration
- by modifying catalina.sh configuration
All I have was a simple FUTEX wait...
And then I read the manual, as simple as :
strace -f -e trace=all -p <PID>
No need to trace from startup and by default, not all is traced...
After that, easy way, the process was reading recursively :
/proc/self/task/81569/cwd/proc/self/task/81569/cwd/proc/self/task/81569/cwd/proc/self/task/81569/cwd/proc/self/task/81569/cwd/proc/self/task/8156...
Just fixing the working_directory in the ansible role, and all is working.
Issue reported here.
Problem :
Following the previous post (this one and this one) I configured a Authorization and Resource server on a a same JVM.
All was working well in my local machine, but when I send the springboot on the server, I get an "Invalid access token". The authorization request was accepted, I get an access token but it was refused by Resource server.
Solution :
I activate remote DEBUG, perform tests (I also had a reverse proxy but that's was not the problem). The issue was due to the tokenStore which :
- on my local machine was the same instance
- on the server was two different instance
In fact depending on the bean initialization order, the token store could be shared or not according to optional Autowire field of the authorization and resource server. If not available at init time, it could use a local instance.
So here is my updated configuration :
My AuthorizationServer
is now :
package com.example;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
public TokenStore tokenStore;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(new MyClientDetailsService());
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.allowFormAuthenticationForClients();
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore);
}
}
And my resource server :
package com.hexagon.hpa.security;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler;
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private static final String RESOURCE_ID = "RESSOURCE_ID";
@Autowired
TokenStore tokenStore;
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID);
resources.tokenStore(tokenStore);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.anonymous().disable()
.authorizeRequests()
.antMatchers("/api/**").authenticated()
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
}
A simple configurer :
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
@Configuration
public class TokenStoreProvider {
@Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
}
Problem :
We are testing a springboot application in AWS with ELB in front.
After a while of load-testing, the application was hanging :
- HTTP 504 error code from Jmeter client
- HTTP 502 if we raise ELB timeout
- Once logged on the server :
- telnet localhost 8080 was OK
- sending GET / on this socket was not responding
- plenty of CLOSE_WAIT socket
- wget was also hanging (normal)
- connection was established during wget hang
- nothing in the log
Solution :
I initially think about the keepAlive timeout and pool of tomcat but
- SpringBoot copy the connectionTimeout parameter to keepAliveTimeout
- new socket is accepted and established
- CLOSE_WAIT wasn't shutdown after hour
Doing the test many times, I finally so a classical "Too many open files" in the log. That's why I could not see more log during the hang.
So we change the nproc and nofile in /etc/security/limits.conf
And taadaaaa ! Nothing change in :
cat /proc/<$PID>/limits
Thanks to blogs over the world like this one :
- the service is start with systemd
- to override ressources limits with systemd :
[Service]
...
LimitNOFILE=500000
LimitNPROC=500000
At last but not least, the value of Tomcat NIO socket queue is around 10000 + other files + other process... choose wisely your limit
Problem :
Edited : due to a bug, see also (https://www.hoab.fr/springboot-2-oauth-2-and-tokenstore)
I try to implements client credentials OAUTH flow for a server which is resource and authentication server. (Goody summary here : https://www.slideshare.net/halyph/oauth2-and-spring-security)
There is plenty of posts on how to make an oauth 2 authentication server, (like authentication code flow less with client_credentials mode...
And in these examples :
But if I easily found how to perform this kind of request : POST + BasicAuth(client_id/client_secret), I wasn't able to do :
POST + optional BasicAuth + client_id/client_secret in post parameters
Solution :
I activate DEBUG on spring security and see that filter chains do not have UsernamePasswordAuthenticationFilter, I plan to add the filter in websecurity as in some examples but it was not working.
After a lot of unsuccessful tries, I finally understand that I have to add a kind of UsernamePasswordAuthenticationFilter on OAUTH2 filter chain and not on the others (yes, there is multiple security filter chain....)
Going back to origins, I check AuthorizationServerConfigurerAdapter
override method and ... eurêka !
As simple as add a
ClientCredentialsTokenEndpointFilter
with
security.allowFormAuthenticationForClients
()
method... So simple, so hard to find.
But my AuthorizationServer
is now :
Due to a bug, the code is now in (https://www.hoab.fr/springboot-2-oauth-2-and-tokenstore)
And a simple (for now) client detail service :
package com.example;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.ClientRegistrationException;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;
import java.util.Arrays;
public class MyClientDetailsService implements ClientDetailsService {
private static final String CLIENT_CREDENTIALS = "client_credentials";
private static final String REFRESH_TOKEN = "refresh_token";
private static final String SCOPE_READ = "read";
private static final String SCOPE_WRITE = "write";
private static final String TRUST = "trust";
private static final int VALID_FOREVER = -1;
private static final String CLIENT_ID = "my-client";
// encoding method prefix is required for DelegatingPasswordEncoder which is default since Spring Security 5.0.0.RC1
// you can use one of bcrypt/noop/pbkdf2/scrypt/sha256
// you can change default behaviour by providing a bean with the encoder you want
// more: https://spring.io/blog/2017/11/01/spring-security-5-0-0-rc1-released#password-encoding
static final String CLIENT_SECRET = "{noop}my-secret";
@Override
public ClientDetails loadClientByClientId(String s) throws ClientRegistrationException {
if (s.equals(CLIENT_ID)) {
BaseClientDetails client = new BaseClientDetails();
client.setClientId(s);
client.setClientSecret(CLIENT_SECRET);
client.setAuthorizedGrantTypes(Arrays.asList(CLIENT_CREDENTIALS, REFRESH_TOKEN));
client.setScope(Arrays.asList(SCOPE_READ, SCOPE_WRITE, TRUST));
client.setAccessTokenValiditySeconds(VALID_FOREVER);
client.setRefreshTokenValiditySeconds(VALID_FOREVER);
return client;
}
return null;
}
}
And my resource server :
Due to a bug, the code is now in (https://www.hoab.fr/springboot-2-oauth-2-and-tokenstore)
The CORS filter from (https://www.hoab.fr/springboot-2-oauth-2-options-and-cors) :
package com.example;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SimpleCorsFilter implements Filter {
public SimpleCorsFilter() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization, content-type");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void destroy() {
}
}
And a protected resource :
package com.example;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/api/metrics")
@RestController
public class Metrics {
@GetMapping
String getToken() {
return "OK";
}
}
Fil RSS des articles