Skip to content
Snippets Groups Projects
Verified Commit 8e619525 authored by Julien Wittouck's avatar Julien Wittouck
Browse files

:sparkles: : add security course

parent 62fd90ce
No related branches found
No related tags found
No related merge requests found
Pipeline #52760 passed
Showing
with 27387 additions and 5 deletions
...@@ -241,6 +241,16 @@ ...@@ -241,6 +241,16 @@
</h5> </h5>
<p class="card-text">On s'authentifie</p> <p class="card-text">On s'authentifie</p>
</div> </div>
<div class="card-footer">
<div class="btn-group" role="group">
<a href="w07-security/07-security.html" class="btn btn-primary" >Cours</a>
<a href="w07-security/07-security.pdf" class="btn btn-secondary"><i class="bi bi-file-earmark-pdf-fill"></i></a>
</div>
<div class="btn-group" role="group">
<a href="w07-security/07-tp-security.html" class="btn btn-primary">TP</a>
<a href="w07-security/07-tp-security.pdf" class="btn btn-secondary"><i class="bi bi-file-earmark-pdf-fill"></i></a>
</div>
</div>
</div> </div>
</div> </div>
<div class="col"> <div class="col">
...@@ -343,11 +353,7 @@ ...@@ -343,11 +353,7 @@
</div> </div>
<div id="footer"> <div id="footer">
<<<<<<< Updated upstream <div id="footer-text" class="index-last-update">Last updated Wed. 30 Oct</div>
<div id="footer-text" class="index-last-update">Last updated Wed. 23 Oct</div>
=======
<div id="footer-text" class="index-last-update">Last updated Wed. 23 Oct</div>
>>>>>>> Stashed changes
</div> </div>
<script <script
......
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>ALOM - Security</title>
<meta name="description" content="ALOM - Security">
<meta name="author" content="Julien WITTOUCK <julien@codeka.io>">
<meta name="apple-mobile-web-app-capable" content="yes"/>
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/>
<meta name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, minimal-ui">
<link rel="stylesheet" href="../reveal/dist/reveal.css">
<link rel="stylesheet" href="../reveal/dist/theme/white.css" id="theme">
<link rel="stylesheet" href="../css/miage-lille.css"/>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css"
integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
</head>
<body>
<div class="reveal">
<div class="slides">
<section>
<h1>ALOM</h1>
<h2>🔒 Security</h2>
</section>
<section>
<h3><i class="fab fa-uber"></i> UBER</h3>
<img src="images/Microservice-Architecture-Of-UBER.png" style="width: 50%"/>
</section>
<section>
<h2>🤔 Problématiques : </h2>
<ul>
<li>Comment sécuriser les données ?</li>
<li>Comment authentifier les utilisateurs ?</li>
</ul>
</section>
<section>
<h2>🎚️ Niveaux de sécurité</h2>
<ul>
<li>Physique : Contrôle d'accès, biométrie</li>
<li>Hardware : Encryption des disques</li>
<li>Middleware : Firewalls (blocage d'IP/Ports), VPN (réseaux privés virtuels)</li>
<li>Software : Authentification/Autorisation</li>
<li>Data : Hashage / Chiffrement</li>
</ul>
</section>
<section>
<section>
<h2>HTTPS</h2>
<p>HTTPS fournit un tunnel de communications sécurisé</p>
<p>Encryption des données via un algorithme asymétrique</p>
<p>Certificat validant l'identité du site + clé publique</p>
</section>
<section>
<h2>HTTPS</h2>
<img src="images/https.png"/>
</section>
<section>
<h2>⚠️ HTTPS</h2>
<ul>
<li>Chiffre les données entre le client et le serveur</li>
<li>Ne permet pas de valider l'identité de l'utilisateur</li>
</ul>
</section>
</section>
<section>
<h2>Software Security</h2>
<ul>
<li>Authentication (authentification)</li>
<li>Authorization (autorisation)</li>
</ul>
</section>
<section>
<h4>Authentication</h4>
<p><i class="far fa-user fa-2x"></i> <i class="far fa-id-card fa-2x"></i></p>
<p>Vérification de l'identité d'un "principal" (un user, un device, un système qui veut effectuer une
action)</p>
</section>
<section>
<h4>Authorization</h4>
<p><i class="fas fa-unlock-alt fa-2x"></i> <i class="fas fa-check fa-2x"></i></p>
<p>Décider si un "principal" peut faire une action en particulier. (contrôle d'accès)</p>
</section>
<section>
<h4>Authentification en HTTP</h4>
<p>Utilisation du header </p>
<p><code>Authorization: &lt;type&gt; &lt;credentials&gt;</code></p>
<p><code>Authorization: Basic QXNoOnBhc3N3b3Jk</code></p>
<p><code>Authorization: Bearer QXNoOnBhc3N3b3Jk</code></p>
</section>
<section>
<h4>Authentification en HTTP</h4>
<p><code>Authorization: Basic QXNoOnBhc3N3b3Jk</code></p>
<p>Les logins/mots de passe (ou tokens) transitent dans les headers</p>
<p>C'est pour ça que l'on doit utiliser HTTPS !</p>
</section>
<section>
<h4>En servlets</h4>
<p>Utilisation des servlet filters</p>
<img src="images/servlet-filters.png"/>
</section>
<section>
<h4>En <img src="images/spring-by-pivotal.png" style="height: 1.5em; vertical-align: middle;"></h4>
<h5>spring-security</h5>
<ul>
<li>Authentification (validation des credentials)</li>
<li>Utilisation d'un Cookie HTTP pour identifiant de session</li>
<li>Stockage de "principal" en session côté serveur</li>
<li>Logout : suppression de la session</li>
<li>Protection contre le vol de session (CSRF & Session Fixation)</li>
<li>Protection contre les appels venant de sources inconnues (CORS)</li>
</ul>
</section>
<section data-markdown>
<textarea data-template>
#### spring-security
```xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
```
Le simple fait d'ajouter spring security au classpath sécurise toutes les routes d'une application et
ajoute une page de login par défaut.
---
#### spring-security
⚠️ Les points listés dans ces slides sont pour Spring Boot 3 et Spring Security 6 (état de l'art)
⚠️ Pour d'anciennes version de Spring Boot (2), les configuration sont différentes, mais les grands principes sont les mêmes
---
#### spring-security
2 _Beans_ importants :
Un bean de type `SecurityFilterChain` permet de configurer les règles de sécurité :
* routes à protéger
* écran de login
Spring Security utilise des `AuthenticationProvider` pour valider les login/mdp ou tokens, et charger des rôles d'accès.
---
#### spring-security
##### `SecurityFilterChain`
```java
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(Customizer.withDefaults())
.authorizeHttpRequests(authorize -> {
authorize.requestMatchers("/unsecured/**").permitAll();
authorize.requestMatchers("/api/**").authenticated();
authorize.requestMatchers("/api/admin/**").hasRole("ADMIN");
authorize.anyRequest().authenticated();
})
.httpBasic(Customizer.withDefaults())
.formLogin(Customizer.withDefaults());
return http.build();
}
}
```
---
#### spring-security
##### `AuthenticationProvider`
Par défaut, Spring Security initialise un `DaoAuthenticationProvider`, qui s'appuie sur un `UserDetailsService`.
```java
@Configuration
public class SecurityConfig {
@Bean
public UserDetailsService userDetailsService() {
UserDetails userDetails = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(userDetails);
}
}
---
#### spring-security
Récupération des utilisateurs via un `UserDetailsService`.
Par défaut, un `UserDetailsService` *in-memory* est créé à partir des properties:
* `spring.security.user.name`
* `spring.security.user.password`
* `spring.security.user.roles`
---
#### spring-security
Configuration d'un `UserDetailsService` avec un Bean Spring.
Un `UserDetailsService` doit retourner des `UserDetails`.
```java
@Autowired
private TrainerService trainerService;
@Bean
@Override
public UserDetailsService userDetailsService() {
return username -> Optional.ofNullable(trainerService.getTrainer(username))
.orElseThrow(() -> new BadCredentialsException("No such user"));
}
```
</textarea>
</section>
<section>
<h4>spring-security</h4>
<p>Page de login</p>
<img src="carbon/login.png"/>
</section>
<section data-markdown>
<textarea data-template>
#### spring-security
Accès à l'utilisateur loggué.
Injection du `java.security.Principal`
```java
@GetMapping("/otherTrainers")
public Iterable<Trainers> getOtherTrainers(Principal principal) {
return trainerRepository.findOtherTrainers(principal.getName());
}
```
`SecurityContextHolder`
```java
@GetMapping("/otherTrainers")
public Iterable<Trainers> getOtherTrainers() {
var auth = SecurityContextHolder.getContext().getAuthentication();
var principal = (Principal) auth.getPrincipal();
return trainerRepository.findOtherTrainers(principal.getName());
}
```
</textarea>
</section>
<section>
<h4>spring-security</h4>
<p>Sécurisation des services REST par défaut</p>
<ul>
<li>Username : <code>user</code></li>
<li>Password : loggué sur la console</li>
</ul>
<code>Using generated security password: 112eb169-1567-42fe-bf0e-7c7bc94a5afa</code>
</section>
<section>
<h4>spring-security</h4>
<p>Personalisation de la sécurisation des services REST</p>
<ul>
<li>Username : <code>spring.security.user.name</code></li>
<li>Password : <code>spring.security.user.password</code></li>
</ul>
</section>
<section data-markdown>
<textarea data-template>
#### spring-security
##### Gestion des rôles.
Un user a des `GrantedAuthority`.
Une `GrantedAuthority` = un *rôle*.
A positionner par les `AuthenticationProvider`, ou par le `UserDetailsService`, dans les objets `UserDetails`.
```java
UserDetails userDetails = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER") // ici ! crée un GrantedAuthority("ROLE_USER")
.build();
```
---
#### spring-security
##### Gestion des rôles.
Autorisations au niveau des méthodes (contrôleur, ou service).
##### Annotations JSR-250 (standard Java, dans `jakarta.annotation-api`)
```java
@Configuration
@EnableMethodSecurity(jsr250Enabled = true)
public class MethodSecurityConfig {
}
```
```java
@RolesAllowed("TRAINER") // sans le "ROLE_"
ModelAndView myTrainerMethod(){...}
```
```java
@RolesAllowed("ADMIN")
ModelAndView myAdminMethod(){...}
```
---
#### spring-security
##### Gestion des rôles.
Autorisations au niveau des méthodes (contrôleur, ou service).
##### Annotations Spring Security [doc](https://docs.spring.io/spring-security/reference/servlet/authorization/method-security.html)
`@PreAuthorize`, `@PostAuthorize`, `@PreFilter`, `@PostFilter`.
```java
@Configuration
@EnableMethodSecurity
public class MethodSecurityConfig {
}
```
```java
@PreAuthorize("hasRole('TRAINER')") // sans le "ROLE_"
ModelAndView myTrainerMethod(){...}
```
```java
@PostAuthorize("returnObject.name == authentication.name")
Trainer someMethod(){...}
```
</textarea>
</section>
<section data-markdown>
<textarea data-template>
#### Recommandation générales
*Kids, don't do this at home*
* Ne stockez **JAMAIS** de mot de passe en clair
* Ne faites **JAMAIS** de concaténation de chaînes pour générer des requêtes SQL
* Évitez de stocker des *secrets* dans des properties (utilisez des variables d'environnement)
* Utilisez du HTTPS et du TLS dès que possible
* Sécurisez vos routes HTTP, utilisez les annotations et les rôles
* Chiffrez les données en base si les données sont sensibles
</textarea>
</section>
<section>
<h2>TP</h2>
<img src="../images/leonidas.png"/>
<p>
<a href="./07-tp-security.html">Security 🔒</a>
</p>
</section>
</div>
</div>
<script src="../reveal/dist/reveal.js"></script>
<script src="../reveal/plugin/markdown/markdown.js"></script>
<link rel="stylesheet" href="../reveal/plugin/highlight/zenburn.css">
<script src="../reveal/plugin/highlight/highlight.js"></script>
<script>
// More info about initialization & config:
// - https://revealjs.com/initialization/
// - https://revealjs.com/config/
Reveal.initialize({
hash: true,
// Learn about plugins: https://revealjs.com/plugins/
plugins: [RevealMarkdown, RevealHighlight],
markdown: {
smartypants: true
}
});
</script>
<aside class="miage_aside_logo"></aside>
</body>
</html>
File added
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
package com.miage.alom.tp.pokemon_ui.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/icons/**", "/images/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
@Bean
@Override
public UserDetailsService userDetailsService() {
UserDetails user =
User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
@Bean
@Override
public UserDetailsService userDetailsService() {
return username -> Optional.ofNullable(trainerService.getTrainer(username))
.map(trainer -> User.withUsername(trainer.getName()).password(trainer.getPassword()).roles("USER").build())
.orElseThrow(() -> new BadCredentialsException("No such user"));
}
}
@GetMapping("/otherTrainers")
public List<Trainers> getOtherTrainers(Principal principal) {
return trainerRepository
.findOtherTrainers(principal.getName());
}
@GetMapping("/otherTrainers")
public List<Trainers> getOtherTrainers() {
SecurityContext
return trainerRepository
.findOtherTrainers(principal.getName());
}
\ No newline at end of file
<form action="/login" method="post">
<div class="form-group">
<label for="username">User Name : </label>
<input type="text" class="form-control" name="username"/>
</div>
<div class="form-group">
<label for="password">Password: </label>
<input type="password" class="form-control" name="password"/>
</div>
<input type="hidden" name="{{_csrf.parameterName}}" value="{{_csrf.token}}"/>
<div>
<input type="submit" class="btn btn-primary" value="Sign In"/>
</div>
</form>
\ No newline at end of file
w07-security/carbon/login.png

103 KiB

w07-security/images/Microservice-Architecture-Of-UBER.png

55.5 KiB

w07-security/images/ash_profile.png

34.3 KiB

w07-security/images/gitlab-app-created.png

30.9 KiB

w07-security/images/gitlab-create-app.png

49.2 KiB

w07-security/images/https.png

38.1 KiB

w07-security/images/login-page.png

6.66 KiB

w07-security/images/postman-edit-collection-authorization.png

36.1 KiB

w07-security/images/postman-edit-collection.png

24 KiB

w07-security/images/servlet-filters.png

16.9 KiB

w07-security/images/spring-by-pivotal.png

11.7 KiB

0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment