Ethickfox kb page with all notes
It provides several essential security features like l, authorization, rolebasedaccesscontrolusingsprings, remembers the password, URL protection, concurrent active sessions management, etc. To enable Spring security in Java Web application, you need to configure three things - declare a delegating proxy filter in web.xml, add the ContextLoaderListener in web.xml and provide actual security constraints on applicationContext-Security.xml file. Since Spring security uses a chain of filters to implement various security constraints, also known as Spring's "security chain filter", it relies on web container for the initialization of delegating filter proxy.
Salt is random data that is combined with a password before password hashing. This makes a dictionary attack more difficult. This process is known as salting. The hashed version of the password is then stored in a database along with salt.
Btw, some hashing algorithms are not suitable for password hashing, if salt is too small or predictable it's possible to recover passwords by matching random words with salt then comparing the hashed version of output with the data stored in the database.
howtoenablesp includes password hashing out of the box. Since version 3.1, Spring Security automatically takes care of salting too. You can use PasswordEncoder implementation to implement password hashing in Spring security. The two important implementations of the new PasswordEncoder interface are BCryptPasswordEncoder and the confusingly named StandardPasswordEncoder based on SHA-256. The BCrypt implementation is the recommended one.
The delegating filter proxy is a generic bean that provides a link between web.xml and application-Context.xml. Spring security uses filters to implement several security related cross-cutting concerns like authentication and authorization.
Since filters need to be declared in the web.xml so that the Servlet container can invoke them before passing the request to the actual Servlet class.
The Spring Security framework uses a chain of filters to apply various security concerns like intercepting the request, detecting (absence of) authentication, redirecting to the authentication entry point, or pass the request to authorization service, and eventually let the request either hit the servlet or throw a security exception (unauthenticated or unauthorized).


The DelegatingFitlerProxy glues these filters together and forms the security filter chain. That's why you see the name "springSecurityFilterChain" when we declare DelegatingFilterProxy as a filter in web.xml.
Here are some of the important filters from Spring's security filter chain, in the order they occur in:
You can add or replace individual filters with your own logic in Spring's security filter chain.
The SecurityContext is used to store the details of the currently authenticated user, also known as a principle. So, if you have to get the username or any other user details, you need to get this SecurityContext first.
The SecurityContextHolder is a helper class, which provides access to the security context. By default, it uses a ThreadLocal object to store security context, which means that the security context is always available to methods in the same thread of execution, even if you don't pass the SecurityContext object around. Don't worry about the ThreadLocal memory leak in web application though, Spring Security takes care of cleaning ThreadLocal.
Object principal = SecurityContextHolder.getContext()
.getAuthentication()
.getPrincipal();
if (principal instanceof UserDetails) {
String username = ((UserDetails)principal).getUsername();
} else {
String username = principal.toString();
}

If you ever need to know current logged-in user details like, in Spring MVC controller, I suggest you declare a dependency and let Spring provide you the Principal object, rather you querying for them and create a tightly coupled system.
@Controller
public class MVCController {
@RequestMapping(value = "/username", method = RequestMethod.GET)
@ResponseBody
public String currentUserName(Principal principal) {
return principal.getName();
}
}
// OR
@Controller
public class SpringMVCController {
@RequestMapping(value = "/username", method = RequestMethod.GET)
@ResponseBody
public String currentUserName(Authentication authentication) {
return authentication.getName();
}
}
You will need to include the following xml snippet in your Spring Security Configuration file mostly named as applicaContext-security.xml. You can name the file whatever you want but just make sure you use the same name in all relevant places
<session-management invalid-session-url="/logout.html">
<concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</session-management>
Проверка подлинности путем проверки введенных имени и пароля с сохраненными в базе
Проверка разрешений на доступ к тому или иному ресурсу


Simply put, Spring Security supports authorization semantics at the method level.
Typically, we could secure our service layer by, for example, restricting which roles are able to execute a particular method — and test it using dedicated method-level security test support.
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
@Configuration
@EnableGlobalMethodSecurity(
prePostEnabled = true,
securedEnabled = true,
jsr250Enabled = true)
public class MethodSecurityConfig
extends GlobalMethodSecurityConfiguration {
}
Annotation is used to specify a list of roles on a method. So, a user only can access that method if she has at least one of the specified roles.
@Secured({ "ROLE_VIEWER", "ROLE_EDITOR" })
public String getUsername() {
SecurityContext securityContext = SecurityContextHolder.getContext();
return securityContext.getAuthentication().getName();
}
The @Secured annotation doesn't support Spring Expression Language (SpEL).
The @RolesAllowed annotation is the JSR-250’s equivalent annotation of the @Secured annotation.
@RolesAllowed("ROLE_VIEWER")
public String getUsername2() {
//...
}
@RolesAllowed({ "ROLE_VIEWER", "ROLE_EDITOR" })
public boolean isValidUsername2(String username) {
//...
}
Both @PreAuthorize and @PostAuthorize annotations provide expression-based access control.
The @PreAuthorize annotation checks the given expression before entering the method, whereas the @PostAuthorize annotation verifies it after the execution of the method and could alter the result.
@PreAuthorize("hasRole('ROLE_VIEWER')")
public String getUsernameInUpperCase() {
return getUsername().toUpperCase();
}
@Service
@PreAuthorize("hasRole('ROLE_ADMIN')")
public class SystemService {
public String getSystemYear(){
//...
}
public String getSystemDate(){
//...
}
}
The @PreAuthorize(“hasRole(‘ROLE_VIEWER')”) has the same meaning as @Secured(“ROLE_VIEWER”), which we used in the previous section.
Moreover, we can actually use the method argument as part of the expression:
@PreAuthorize("\#username == authentication.principal.username")
public String getMyRoles(String username) {
//...
}
@PostAuthorize annotation provides the ability to access the method result:
@PostAuthorize("returnObject.username == authentication.principal.nickName")
public CustomUser loadUserDetail(String username) {
return userRoleRepository.loadUserByUserName(username);
}
Method Security Meta-Annotation
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@PreAuthorize("hasRole('VIEWER')")
public @interface IsViewer {
}
//usage
@IsViewer
public String getUsername4() {
//...
}
Security expressions:
hasRole****, hasAnyRole
hasAuthority****, hasAnyAuthority
Roles and authorities are similar in Spring.
The main difference is that roles have special semantics. Starting with Spring Security 4, the ‘ROLE_‘ prefix is automatically added (if it's not already there) by any role-related method.
So hasAuthority(‘ROLE_ADMIN') is similar to hasRole(‘ADMIN') because the ‘ROLE_‘ prefix gets added automatically.
permitAll****, denyAll
isAnonymous****, isAuthenticated,
**_isRememberMe
_**Through the use of cookies, Spring enables remember-me capabilities, so there's no need to log into the system each time.
**_isFullyAuthenticated
_**If some parts of our services require the user to be authenticated again, even if the user is already logged in.
principal****, authentication
These expressions allow us to access the principal object representing the current authorized (or anonymous) user and the current Authentication object from the SecurityContext, respectively.
We can, for example, use principal to load a user's email, avatar, or any other data that's accessible from the logged-in user.
**_hasPermission
_**This expression is intended to be a bridge between the expression system and Spring Security’s ACL system, allowing us to specify authorization constraints on individual domain objects based on abstract permissions.
@PreAuthorize("hasPermission(\#article, 'isEditor')")
public void acceptArticle(Article article) {
…
}
Only the authorized user can call this method, and they need to have isEditor permission in the service.
RESTful web services can be authenticated in many ways, but the most basic one is basic authentication. For basic authentication, we send a username and password using the HTTP [Authorization] header to enable us to access the resource. Usernames and passwords are encoded using base64 encoding (not encryption) in Basic Authentication. The encoding is not secure since it can be easily decoded.
@Bean
public UserDetailsService userDetails(){
UserDetails userDetails = User.withDefaultPasswordEncoder()
.username("user")
.password("qwe")
.roles(Role.USER.name())
.build();
UserDetails adminDetails = User.withDefaultPasswordEncoder()
.username("admin")
.password("qwe")
.roles(Role.ADMIN.name())
.build();
return new InMemoryUserDetailsManager(userDetails, adminDetails);
}
@Bean
public UserDetailsService userDetails(DataSource dataSource) {
return new JdbcUserDetailsManager(dataSource);
}
Configuration
@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((auth) -> auth
.requestMatchers("/","/home").permitAll()
.requestMatchers("/flats").hasRole("USER")
.requestMatchers("/users").hasRole("ADMIN")
.anyRequest().authenticated()
)
.httpBasic(withDefaults());
return http.build();
}
password encoder, default - bcrypt
@Bean
public PasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance();
}



As far as security is concerned, session management relates to securing and managing multiple users' sessions against their request. It facilitates secure interactions between a user and a service/application and pertains to a sequence of requests and responses associated with a particular user. Session Management is one of the most critical aspects of Spring security as if sessions are not managed properly, the security of data will suffer. To control HTTP sessions, Spring security uses the following options:
OAuth is an open standard that describes a process of authorization. It can be used to authorize user access to an API. For example, a REST API can restrict access to only registered users with a proper role.
An OAuth authorization server is responsible for authenticating the users and issuing access tokens containing the user data and proper access policies.
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-authorization-server</artifactId>
<version>0.2.0</version>
</dependency>




@Configuration
@Import(OAuth2AuthorizationServerConfiguration.class)
public class AuthorizationServerConfig {
@Bean
public RegisteredClientRepository registeredClientRepository() {
RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("articles-client")
.clientSecret("{noop}secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.redirectUri("http://127.0.0.1:8080/login/oauth2/code/articles-client-oidc")
.redirectUri("http://127.0.0.1:8080/authorized")
.scope(OidcScopes.OPENID)
.scope("articles.read")
.build();
return new InMemoryRegisteredClientRepository(registeredClient);
}
}
The properties we're configuring are:
Configure a bean to apply the default OAuth security and generate a default form login page:
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
return http.formLogin(Customizer.withDefaults()).build();
}
@EnableWebSecurity
public class DefaultSecurityConfig {
@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeRequests(authorizeRequests ->
authorizeRequests.anyRequest().authenticated()
)
.formLogin(withDefaults());
return http.build();
}
// ...
}
Each authorization server needs its signing key for tokens to keep a proper boundary between security domains.
@Bean
public JWKSource<SecurityContext> jwkSource() {
RSAKey rsaKey = generateRsa();
JWKSet jwkSet = new JWKSet(rsaKey);
return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
}
private static RSAKey generateRsa() {
KeyPair keyPair = generateRsaKey();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
return new RSAKey.Builder(publicKey)
.privateKey(privateKey)
.keyID(UUID.randomUUID().toString())
.build();
}
private static KeyPair generateRsaKey() {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
return keyPairGenerator.generateKeyPair();
}
@Bean
public ProviderSettings providerSettings() {
return ProviderSettings.builder()
.issuer("http://auth-server:9000")
.build();
}


@EnableWebSecurity
конфигурация(содержит @Configuration) для Spring Security
Объект, который имеет какие-то ограничения, по правам доступа, которые могут к нему обратиться
основной интерфейс стратегии для аутентификации. Он отвечает за проверку аутентификации.
содержит объект Authentication и в случае необходимости информацию системы безопасности, связанную с запросом от пользователя.
класс для переопределения настроек Security. Переопрепределяется configure
класс для создания и настройки пользователей
настройки доступа для http запросов
Authentication is a process to verify that the user is the one who he claims to be. It is generally implemented using a username and password. If a user enters the correct username and password then authentication is successful, otherwise, authentication failed.

Authorisation provides access control. For example, only the admin can see some pages in a web application. To implement that, the admin must have some admin-related permissions or roles.

