SpringSecurity etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
SpringSecurity etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

3 Eylül 2023 Pazar

SpringSecurity JwtAuthenticationProvider Sınıfı

Giriş
Şu satırı dahil ederiz
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider;
Şeklen şöyle


Açıklaması şöyle
... Spring directs the incoming request to the right Authentication Provider (JwtAuthenticationProvider) through the AuthenticationManager. This provider is in charge of decoding and verifying the JWT access token. The provider then uses JwtAuthenticationConverter to turn the raw JWT into an AbstractAuthenticationToken. By default, it uses JwtGrantedAuthoritiesConverter at this step. The job of JwtGrantedAuthoritiesConverter is to change the incoming JWT into granted authorities.

By default, JwtGrantedAuthoritiesConverter splits the claim based on the “scope” or “scp” tags and turns it into a list of strings. After that, for each value, it adds the ‘SCOPE_’ prefix and creates a SimpleGrantedAuthority.
Örnek 
Şöyle yaparız
// Custom converter that splits based on the roles in the ‘roles’ claim 
// and fixing the prefix part.
private final class CustomJwtGrantedAuthoritiesConverter implements 
  Converter<Jwt, Collection<GrantedAuthority>> {

  @Override
  public Collection<GrantedAuthority> convert(Jwt jwt) {
    var realmAccess = (Map<String, List<String>>) jwt.getClaim("realm_access");

    return realmAccess.get("roles").stream()
      .map(role -> new SimpleGrantedAuthority("ROLE_" + role))
      .collect(Collectors.toList());
    }

  @Override
  public <U> Converter<Jwt, U> andThen(Converter<? super Collection<GrantedAuthority>, ? extends U> after) {
    return Converter.super.andThen(after);
  }
}

// override the JwtAuthenticationConverter bean and set the // CustomJwtGrantedAuthoritiesConverter.
@Bean
public JwtAuthenticationConverter customJwtAuthenticationConverter() {
  JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
  converter.setJwtGrantedAuthoritiesConverter( new CustomJwtGrantedAuthoritiesConverter());
  return converter;
}

// give JwtAuthenticationConverter to the SecurityFilterChain.
@Bean
protected SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

  return http
    .csrf(AbstractHttpConfigurer::disable)
    .authorizeHttpRequests(requests ->
      requests
        .anyRequest().authenticated()
      )
      .oauth2ResourceServer(oauth2 ->
        oauth2.jwt(jwt ->
          jwt.jwtAuthenticationConverter(customJwtAuthenticationConverter())
        )
      )
      .build();
}



7 Haziran 2023 Çarşamba

SpringSecurity SecurityFilterChain.formLogin metodu

Örnek
Şöyle yaparız
@Configuration
public class SecurityConfiguration {
  @Bean
  SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {

    //CUSTOM SECURITY
    httpSecurity.csrf().disable()
    ...
    .and().formLogin()
    ...
    return httpSecurity.build();
  }
}
Örnek
Şöyle yaparız
httpSecurity
  .formLogin(AbstractHttpConfigurer::disable)
  ...

SpringSecurity SecurityFilterChain.authorizeHttpRequests metodu

Örnek
Şöyle yaparız
httpSecurity
...
  .authorizeHttpRequests(authorizeHttpRequests -> authorizeHttpRequests
                .anyRequest()
                .permitAll())
...;

6 Haziran 2023 Salı

SpringSecurity FilterSecurityInterceptor Sınıfı

Giriş
Açıklaması şöyle
This filter is used to enforce security constraints on HTTP requests based on the configured security rules.

SpringSecurity SessionManagementFilter Sınıfı

Giriş
Açıklaması şöyle
We use this to manage user sessions and prevent session hijacking.

SpringSecurity BasicAuthenticationFilter Sınıfı

Giriş
Açıklaması şöyle
This filter is used to authenticate a user using basic authentication.

24 Nisan 2023 Pazartesi

SpringSecurity ServerAuthenticationEntryPoint Arayüzü - WebFlux İle Kullanılır

Örnek
Şöyle yaparız
mport org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

public class CustomAuthenticationEntryPoint implements ServerAuthenticationEntryPoint {

    //Authentication entry point has commence method when failures occur
    @Override
    public Mono<Void> commence(ServerWebExchange exchange, AuthenticationException ex) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        return new AuthFailureHandler().formatResponse(response);
    }
}

SpringSecurity ServerAccessDeniedHandler Arayüzü - WebFlux İle Kullanılır

Örnek
Şöyle yaparız
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

public class CustomAccessDeniedHandler implements ServerAccessDeniedHandler {

  //Access Denied / unauthorized has handle method when failures occur
  @Override
  public Mono<Void> handle(ServerWebExchange exchange, AccessDeniedException accessDeniedException) {
    ServerHttpResponse response = exchange.getResponse();
    response.setStatusCode(HttpStatus.FORBIDDEN);
    return new AuthFailureHandler().formatResponse(response);
  }
}
Cevabı formatlayan kod şöyledir
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.godwinpinto.authable.application.rest.auth.json.ApiResponse;
import lombok.NoArgsConstructor;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

@NoArgsConstructor
public class AuthFailureHandler {

 public Mono<Void> formatResponse(ServerHttpResponse response) {
   response.getHeaders()
     .add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
   ObjectMapper mapper = new ObjectMapper();
   ApiResponse apiResponse = new ApiResponse(response.getStatusCode()
     .value(), "Access Denied", null);
   StringBuilder json = new StringBuilder();
   try {
     json.append(mapper.writeValueAsString(apiResponse));
   } catch (JsonProcessingException jsonProcessingException) {
   }

   String responseBody = json.toString();
   byte[] bytes = responseBody.getBytes(StandardCharsets.UTF_8);
   DataBuffer buffer = response.bufferFactory()
     .wrap(bytes);
   return response.writeWith(Mono.just(buffer));
  }
}

14 Şubat 2023 Salı

SpringSecurity OAuth2 Authorization Server Gerçekleştirimi

Gradle
Şu satırı dahil ederiz
implementation 'org.springframework.security:spring-security-oauth2-authorization-server:1.0.0'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'

testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
1. OAuth2AuthorizationServerConfiguration Bean tanımla
Şöyle yaparız
import org.springframework.security.oauth2.server.authorization.config.annotation
.web.configuration.OAuth2AuthorizationServerConfiguration; @Bean @Order(Ordered.HIGHEST_PRECEDENCE) public SecurityFilterChain authServerSecurityFilterChain(HttpSecurity http) throws Exception { OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http); return http.build(); }
2. RegisteredClientRepository Bean Tanımla
Şöyle yaparız
import org.springframework.security.oauth2.server.authorization.client
  .InMemoryRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;


@Bean
public RegisteredClientRepository registeredClientRepository() {
  RegisteredClient registeredClient 
    = RegisteredClient.withId(UUID.randomUUID().toString())
    .clientId("oauth-client")
    .clientSecret("{noop}oauth-secret")
    .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
    .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
    .scope(OidcScopes.OPENID)
    .scope("articles.read")
    .build();
  return new InMemoryRegisteredClientRepository(registeredClient);
}
3. JWT Decoder Tanımla
Şöyle yaparız
@Bean
public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
    return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
}
Public ve private key yaratmak şöyle
@Bean
public JWKSource<SecurityContext> jwkSource() throws NoSuchAlgorithmException {
    RSAKey rsaKey = generateRsa();
    JWKSet jwkSet = new JWKSet(rsaKey);
    return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
}

private static RSAKey generateRsa() throws NoSuchAlgorithmException {
    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() throws NoSuchAlgorithmException {
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
    keyPairGenerator.initialize(2048);
    return keyPairGenerator.generateKeyPair();
}
4. AuthorizationServerSettings Bean Tanımla
Şöyle yaparız
@Bean
public AuthorizationServerSettings authorizationServerSettings() {
    return AuthorizationServerSettings.builder().build();
}
Token almak için şöyle yaparız
curl -X POST 'http://localhost:9090/oauth2/token?grant_type=client_credentials' \
  --header 'Authorization: Basic b2F1dGgtY2xpZW50Om9hdXRoLXNlY3JldA=='
Burada Basic'ten gelen string base64 encoded. Açılmış hali şöyle
oauth-client:oauth-secret
Gelen cevap şöyle
{
  "access_token": "...",
  "token_type": "Bearer",
  "expires_in": 299
}



3 Ocak 2023 Salı

SpringSecurity SecurityWebFilterChain Sınıfı - WebFlux İçin Yeni Component Base Approach

oauth2Login metodu
Şu satırı dahil ederiz
implementation ("org.springframework.boot:spring-boot-starter-oauth2-client:2.7.2")
implementation ("org.springframework.boot:spring-boot-starter-webflux:2.7.2")
Açıklaması şöyle
PKCE (pronounced “pixy”) stands for “Proof Key for Code Exchange.” It is a security mechanism that is used to protect authorization code grants when used with OAuth 2.0 and OpenID Connect.

When an application wants to access a user’s resources on a resource server (such as an API), the application must first obtain an authorization code from the authorization server. This authorization code can then be exchanged for an access token, which allows the application to access the user’s resources.

However, this process can be vulnerable to attacks if the authorization code is intercepted by an attacker. PKCE was introduced to protect against this type of attack by requiring the application to include additional information, called a “code verifier,” when requesting the authorization code. The authorization server includes this code verifier when issuing the authorization code, and the application must provide it again when exchanging the authorization code for an access token. This ensures that the application is the one that initiated the request, rather than an attacker who may have intercepted the authorization code.

PKCE is particularly important when an application is using the authorization code grant type in a native application, as it is more vulnerable to code interception attacks.

PKCE will be mandatory with the authorization code flow in OAUTH 2.1

Until recently, developers had to implement bespoke component in their spring app to get around this limitation. Fortunately, Spring security 5.7 supports natively PKCE.

By default it’s deactivated as there’re still some authorisation servers which don’t support PKCE. We’ll see below how to enable this feature.

Örnek
Şöyle yaparız
@Bean
public SecurityWebFilterChain pkceFilterChain(
  ServerHttpSecurity http,
  ServerOAuth2AuthorizationRequestResolver pkceResolver) {

  http.authorizeExchange(r -> r.anyExchange().authenticated());
  http.oauth2Login(auth -> auth.authorizationRequestResolver(pkceResolver));
  return http.build();
}

@Bean
public ServerOAuth2AuthorizationRequestResolver getPkceResolver(
  ReactiveClientRegistrationRepository reactiveRepo) {
    
  var pkceResolver = new DefaultServerOAuth2AuthorizationRequestResolver(reactiveRepo);
  pkceResolver.setAuthorizationRequestCustomizer( OAuth2AuthorizationRequestCustomizers.withPkce());
  return pkceResolver;
}

26 Aralık 2022 Pazartesi

SpringSecurity @EnableMethodSecurity Anotasyonu

Giriş
SpringBoot 3 ile geliyor. Eski @EnableGlobalMethodSecurity ile aynı şeyi yapıyor. Method level security sağlar. Security için @Secured, @RoleAllowed, @PreAuthorize anotasyonları kullanılır
Örnek
Şöyle yaparız
// This is Deprecated
@EnableGlobalMethodSecurity(securedEnabled = true
  jsr250Enabled = true, prePostEnabled = true)
public class SecurityConfig{}

// Use Enable Method Security, prePost is Enabled by Default
@EnableMethodSecurity(securedEnabled = true, jsr250Enabled = true)
public class SecurityConfig{}



12 Eylül 2022 Pazartesi

SpringSecurity SecurityFilterChain Sınıfı - Yeni Component Based Approach

Giriş
Açıklaması şöyle
With Spring Security 5 a security configuration class or classes would normally inherit WebSecurityConfigurerAdapter and override the configure method.

In Spring Security 6, it is now a Bean that takes HttpSecurity object as a parameter and returns SecurityFilterChain object.
WebSecurityConfigurerAdapter sınıfından kalıtıp "configure(HttpSecurity http)" metodunu override etmek yerine, kendimiz bir SecurityFilterChain döndürüyoruz. 

Bu sınıfı oluşturturken lambda'lar ağırlıklı olarak kullanılıyor. 

SpringBoot 3 ile Gelen Farklılıklar
1. antMatchers() yerine requestMatchers() metodu kullanılıyor
Açıklaması şöyle
One change requires source modification: with Spring Security 5, we used .antMatchers method of authorizeRequest object. With Spring Security 6, it has been renamed to .requestMatchers. Otherwise, everything is as it was before, except that this method must now have a call to create SecurityFilterChain object from http parameter by calling http.build().
2. Açıklaması şöyle. Yani iki tane yıldız olmak zorunda
After switching to Spring Security 6, the previous configuration does not work any longer. In order to handle requests properly, it has to be as follows :

.requestMatchers(HttpMethod.GET,"/ws/user/**",
addFilterBefore metodu
Örnek
Şöyle yaparız
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { 
  http
    .csrf()
    .disable()

    // Add Paseto token filter
    .addFilterBefore(authTokenFilter, UsernamePasswordAuthenticationFilter.class)
    .authenticationProvider(authenticationProvider())

    // Set unauthorized requests exception handler
    .exceptionHandling()
        .authenticationEntryPoint(new HandlerAuthenticationEntryPoint())
        .accessDeniedHandler(new HandlerAccessDeniedHandler())
    .and()
      .sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
    .and()

      // Set permissions on endpoints
      .authorizeHttpRequests()
      .requestMatchers("/api/account/authenticate").permitAll()
      .requestMatchers("/api/account/register").permitAll()
      .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
      .requestMatchers(
        "/configuration/ui",
        "/swagger-resources/**",
        "/configuration/security",
        "/webjars/**").permitAll()
        .requestMatchers("/api/**").authenticated();
      
  return http.build();
}
authorizeHttpRequests  metodu
SecurityFilterChain.authorizeHttpRequests metodu yazısına taşıdım

csrf metodu
CsrfConfigurer yazısına taşıdım

cors metodu
Örnek
Şöyle yaparız
@Configuration
@EnableWebSecurity public class WebSecurityConfig { ... @Bean public SecurityFilterChain auth0FilterChain(HttpSecurity http) throws Exception { http.cors() .and() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .securityMatcher("/ws/**") .authorizeHttpRequests(autorizeRequests -> autorizeRequests .requestMatchers(HttpMethod.GET, "/ws/healthz", "/ws/ready", "/ws/version") .permitAll() .requestMatchers(HttpMethod.GET, "/ws/user/**","/ws/user/avatar/*","/ws/user/search") .hasAnyAuthority("SCOPE_tmt:user") .requestMatchers(HttpMethod.POST, "/ws/friend","/ws/user/trip", "/ws/trip/*") .hasAnyAuthority("SCOPE_tmt:user") ) .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt); http.csrf().disable(); http.headers().frameOptions().disable(); return http.build(); } }
Örnek
Şöyle yaparız
// Spring Boot 3.0.0
@Bean
protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  // ...
  http.authorizeHttpRequests()
    // Public endpoints
    .requestMatchers(HttpMethod.GET, "/swagger-ui.html").permitAll()
    .requestMatchers(HttpMethod.GET, "/swagger-ui/**").permitAll()
    .requestMatchers(HttpMethod.GET, "/v3/api-docs/**").permitAll()
    .requestMatchers(HttpMethod.POST, "/api/auth/login").permitAll()
    .requestMatchers(HttpMethod.POST, "/api/auth/token-refresh").permitAll()
    .anyRequest().authenticated();
    // ...
}
exceptionHandling metodu
accessDeniedHandler için ServerAccessDeniedHandler nesnesi takılır
authenticationEntryPoint hatası için ServerAuthenticationEntryPoint nesnesi takılır
Örnek
Şöyle yaparız
@Configuration
@EnableWebFluxSecurity //webflux related
@EnableReactiveMethodSecurity //webflux related
public class SecurityConfig {

  //whitlisting swagger urls
  private static final String[] AUTH_WHITELIST = {
    // -- swagger ui
    "/swagger-resources/**",
    "/configuration/ui",
    "/configuration/security",
    "/swagger-ui.html",
    "/webjars/**",
    "/v3/api-docs/**"};

  //custom auth classes for validating JWT
  @Autowired
  private AuthenticationManager authenticationManager;
    
  //custom auth classes for validating JWT
  @Autowired
  private SecurityContextRepository securityContextRepository;

  @Bean
  SecurityWebFilterChain springSecurityFilterChain(final ServerHttpSecurity http) {
     http.csrf()
       .disable()
       //Disable Sessions
       .securityContextRepository(NoOpServerSecurityContextRepository.getInstance())
       // handlers fro 401 and 403
       .exceptionHandling(exception -> exception.accessDeniedHandler(new CustomAccessDeniedHandler())
         .authenticationEntryPoint(new CustomAuthenticationEntryPoint()))
       //rest services don't have a login form
       .formLogin()
       .disable()
       //disabled basic authentication
       .httpBasic()
       .disable()
       .authorizeExchange()
       //used when connecting from browsers
       .pathMatchers(HttpMethod.OPTIONS)
       .permitAll()
       //other whitelist URL, like swagger. ensure to disable in production
       .pathMatchers(AUTH_WHITELIST)
       .permitAll()
       //your auth URL
       .pathMatchers("/auth/login")
       .permitAll()
       .and()
       //spring authentication manager
       .authenticationManager(authenticationManager)
       .securityContextRepository(securityContextRepository)
       .authorizeExchange()
       .anyExchange()
       .authenticated()
       .and();
       return http.build();
    }
}

formLogin metodu
SecurityFilterChain.formLogin metodu  metodu yazısına taşıdım

oauth2ResourceServer metodu


7 Aralık 2021 Salı

SpringSecurity AuthenticationException Sınıfı - Tüm Authentication Exceptionlarının Atası

Giriş
Şu satırı dahil ederiz
import org.springframework.security.core.AuthenticationException;
Açıklaması şöyle
Abstract superclass for all exceptions related to an Authentication object being invalid for whatever reason.
Bu sınıftan kalıtan bazı sınıflar şöyle
AccountStatusException, 
ActiveDirectoryAuthenticationException, 
AuthenticationCancelledException, 
AuthenticationCredentialsNotFoundException, 
AuthenticationServiceException, 
BadCredentialsException, 
InsufficientAuthenticationException, 
NonceExpiredException, 
OAuth2AuthenticationException, 
PreAuthenticatedCredentialsNotFoundException, 
ProviderNotFoundException, 
RememberMeAuthenticationException, 
Saml2AuthenticationException, 
SessionAuthenticationException, 
UsernameNotFoundException


SpringSecurity AuthenticationSuccessHandler Arayüzü

Giriş
Şu satırı dahil ederiz
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
Açıklaması şöyle
It has the direct responsibility of deciding what to do after a successful authentication (like controlling the navigation based on the authenticated user’s role to the subsequent destination using a redirect or a forward).

You can also set headers to response or save a token value to a cache or save an audit log as a successful login.

Ready to Use Handlers (within Spring Security):

AbstractAuthenticationTargetUrlRequestHandler,
SimpleUrlAuthenticationSuccessHandler
Şeklen şöyle




SpringSecurity AbstractAuthenticationProcessingFilter Sınıfı

Giriş
Şu satırı dahil ederiz
import org.springframework.security.web.authentication
  .AbstractAuthencticationProcessingFilter;
Açıklaması şöyle
This filter will intercept a (browser-based HTTP-based authentication) request and attempt to perform authentication from that request if the request url path matches.

You define a request matcher for matching urls (provided with a direct filter url string value or RequestMatcher object), success and fail handlers and an authentication manager inside which the authentication flow will take place, processing the provided authentication request token.

It has a “attemptAuthentication” method where you can build up your custom “AbstractAuthenticationToken” request class and pass to the authentication manager’s “authenticate” method.
Kalıtan bazı sınıflar şöyle
CasAuthenticationFilter, 
OpenIDAuthenticationFilter, 
UsernamePasswordAuthenticationFilter — default responds to the URL “/login” which used to be “/j_spring_security_check” before.


21 Eylül 2021 Salı

SpringSecurity OAuth2 Client ClientRegistration Sınıfı

Giriş
Şu satırı dahil ederiz
import org.springframework.security.oauth2.client.registration.ClientRegistration;
ClientRegistration Nedir?
Açıklaması şöyle
A client registration holds information, such as client id, client secret, authorization grant type, redirect URI, scope(s), authorization URI, token URI, and other details.
Örnek
Şöyle yaparız
private ClientRegistration createClientRegistration() {
  return ClientRegistration.withRegistrationId("onelogin")
      .clientId(oneLoginConfigs.getClientId())
      .clientSecret(oneLoginConfigs.getClientSecret())
      .clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
      .authorizationUri("https://company.onelogin.com/oidc/2/auth")
      .tokenUri("https://company.onelogin.com/oidc/2/token")
    
  .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
      .redirectUri("{baseUrl}/login/oauth2/code/{registrationId}")
      .scope("openid", "profile", "email”)
      .userInfoUri("https://company.onelogin.com/oidc/2/me")
      .userNameAttributeName(IdTokenClaimNames.SUB)
      .jwkSetUri("https://company.onelogin.com/oidc/2/certs")
      .clientName("Zoo")
      .build();
}

SpringSecurity OAuth2 Client ClientRegistrationRepository Arayüzü

Giriş
Şu satırı dahil ederiz
import org.springframework.security.config.annotation.web.configurers.oauth2.client.
registration.ClientRegistrationRepository;
Bu arayüzden sadece InMemoryClientRegistrationRepository kalıtır

InMemoryClientRegistrationRepository Sınıfı
ClientRegistration yazısına bakabilirsiniz

constructor - ClientRegistration
Örnek
Şöyle yaparız
@Bean
public ClientRegistrationRepository clientRegistrationRepository() {
  return new InMemoryClientRegistrationRepository(createClientRegistration());
}

private ClientRegistration createClientRegistration() {
  ...
}

17 Eylül 2021 Cuma

SpringSecurity WebSecurityConfigurerAdapter Çoklu Realm

Giriş
Çoklu realm neden gerekir? Çünkü farklı url adreslerine farklı doğrulama yöntemleri uygulamak isteyebiliriz.

Normalde WebSecurityConfigurerAdapter bir tane realm'e denk gelir. Eğer farklı adresler/servisler için farklı authentication mekanizması kullanmak istiyorsak, bu sınıftan bir kaç tane yaratmak gerekebilir. Bu yöntemde farklı realm'lerin AuthenticationProvider'ları birbirlerini görmezler

Genel Kullanım
WebSecurityConfigurerAdapter sınıfından birden fazla yaratacağımız için @Orderer ile birlikte kullanmak gerekir
Şöyle yaparız
@Configuration
@EnableWebSecurity
@Order(1)
public class FooSecurityConfiguration extends WebSecurityConfigurerAdapter {
  ...
}
Bir örnek burada. Bir başka örnek burada

Şeklen şöyle

Örnek
Şöyle yaparız
@Configuration
@EnableWebSecurity(debug=true)
public class MultipleSecurityCofig extends WebSecurityConfigurerAdapter {
  @Order(1)
  @Configuration
  public  static class EmployeeConfig extends WebSecurityConfigurerAdapter{
    @Override
    protected void configure(HttpSecurity http) throws Exception {
      http.antMatcher("/api/v1/employee/**").authorizeRequests()
.antMatchers("/api/v1/employee/**").permitAll()
        .and().sessionManagement().disable()
        .cors().disable()
        .csrf().disable()
        .logout().disable()
        .requestCache().disable()
        .headers().disable();
    }
  }

  @Order(2)
  @Configuration
  public static class ManagerConfig extends WebSecurityConfigurerAdapter{
    @Override
    protected void configure(HttpSecurity http) throws Exception {
      http.antMatcher("/api/v1/manager/**").authorizeRequests()
.antMatchers("/api/v1/manager/**").permitAll()
        .and().addFilterAfter(new AuditLogFilter(), FilterSecurityInterceptor.class);
    }
  }
}
Manager için takılan filtre şöyledir
public class AuditLogFilter implements Filter {
  public static final Logger log = LoggerFactory.getLogger(AuditLogFilter.class);

  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
  throws IOException, ServletException {
    log.info("Manager Login Detected at {} ",Instant.now());
    chain.doFilter(request, response);
  }
  @Override
  public void init(FilterConfig filterconfig) throws ServletException {
  }

  @Override
  public void destroy() {
  }
}


SpringSecurity Keycloak

Giriş
Açıklaması şöyle
Keycloak is an open-source identity and access management solution which makes it easy to secure modern applications and services with little to no code.
Keycloak Deployment
Açıklaması şöyle
There are many ways to deploy Keycloak.
1. Standalone Deployment with Keycloak Distribution Files
2. Standalone Deployment with Docker
3. High Availability Deployment in Kubernetes
Kurulumu yaptıktan sonra dizinlerin açıklaması şöyle
bin: This contains various scripts to either boot the server or performs some other management action on the server.
domain: This contains configuration files and working directory when running Keycloak in domain mode.
modules: These are all the Java libraries used by the server.
standalone: This contains configuration files and working directory when running Keycloak in standalone mode.
Çalıştırmak
Çalıştırmak için bin\standalone.bat kullanılır. 
Daha sonra http://localhost:8080 adresinden giriş yaparız. 

Örnek  - dev  olarak çalıştırmak
Şöyle yaparız
{KEYCLOAK_HOME}\bin\kc.sh start-dev

Admin Kullanıcısı
Önce bir admin kullanıcısı yaratmak gerekir. Admin kullanıcısı master realm altındadır.

Realm
Daha sonra yeni bir realm yaratırız. Açıklaması şöyle
A Realm manages a set of users, credentials, roles, and groups. A user belongs to and logs into a realm. Realms are isolated from one another and can only manage and authenticate the users that they control.
Client
Daha sonra yeni realm altında bir client yaratırız. Açıklaması şöyle
Clients are entities that can request Keycloak to authenticate a user. Most often, clients are applications and services that want to use Keycloak to secure themselves and provide a single sign-on solution. Clients can also be entities that just want to request identity information or an access token so that they can securely invoke other services on the network that are secured by Keycloak.
Role
Daha sonra realm altında role yaratırız. Açıklaması şöyle
Applications often assign access and permissions to specific roles rather than individual users as dealing with users can be too fine grained and hard to manage.
Daha sonra realm altında user yaratırız

kcadm komutu
Yukarıdaki adımlar komut satırından yapmak kcadm komutu ile mümkün. Şöyle yaparız
# login
./kcadm.sh config credentials 
  --server http://localhost:8080 
  --realm master 
  --user admin --password admin

# create realm
./kcadm.sh create realms 
  -s realm=spring-boot-keycloak 
  -s enabled=true 
  -o 
  -s defaultSignatureAlgorithm=RS512

# create the client that we are going to use
./kcadm.sh create clients 
  -r spring-boot-keycloak 
  -f {FILE_PATH}/client-id.json 
  -s clientId=spring-boot-keycloak-country-api-client 
  -s enabled=true

# create the client secret
# Get clientId
./kcadm.sh get clients -r spring-boot-keycloak --fields id,clientId

./kcadm.sh create clients/CLIENT_ID_FROM_PREVIOUS_STEP/client-secret 
  -r spring-boot-keycloak
Sonra rolleri yaratırız. Şöyle yaparız
# create roles
./kcadm.sh create roles -r spring-boot-keycloak -s name=manager
./kcadm.sh create roles -r spring-boot-keycloak -s name=user

# create users
./kcadm.sh create users -r spring-boot-keycloak 
  -s username=john.smith -s enabled=true

# Set password
./kcadm.sh update users/{USER_ID_FROM_PREVIOUS_COMMAND}/reset-password 
  -r spring-boot-keycloak -s type=password -s value=password -s temporary=false -n

./kcadm.sh create users -r spring-boot-keycloak -s username=jane.doe -s enabled=true

# Set password
./kcadm.sh update users/{USER_ID_FROM_PREVIOUS_COMMAND}/reset-password 
  -r spring-boot-keycloak -s type=password -s value=password -s temporary=false -n
Kullanıcılara rolleri atarız. Şöyle yaparız
./kcadm.sh add-roles --uusername john.smith --rolename manager -r spring-boot-keycloak
./kcadm.sh add-roles --uusername jane.doe --rolename user -r spring-boot-keycloak

Access Token
Örnek
http://keycloak.demo.com/auth/realms/Keycloak-Demo/protocol/openid-connect/token
adresine x-www-form-urlencoded olarak  POST istek göndeririz. Alanları doldurmak için şöyle yaparız
grant_type : password
client_id : ...
client_secret : ...
username : ...
password : ...

Maven
Şu satırı dahil ederiz
<dependency>
  <groupId>org.keycloak</groupId>
  <artifactId>keycloak-spring-boot-starter</artifactId>
  <version>10.0.1</version>
</dependency>
KeycloakWebSecurityConfigurerAdapter  Sınıfı
Açıklaması şöyle
Keycloak provides a KeycloakWebSecurityConfigurerAdapter as a convenient base class for creating a WebSecurityConfigurer instance. The implementation allows customization by overriding methods. While its use is not required, it greatly simplifies your security context configuration.

Örnek
Sınıfın iskeleti için şöyle yaparız
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
import org.keycloak.adapters.springsecurity.KeycloakSecurityComponents;
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
class KeycloakSecurityConfiguration extends KeycloakWebSecurityConfigurerAdapter {
  ...
}
configureGlobal metodu
Açıklaması şöyle
Registers the KeycloakAuthenticationProvider with the authentication manager.
Şöyle yaparız
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
  KeycloakAuthenticationProvider keycloakAuthenticationProvider =
keycloakAuthenticationProvider();
  keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
  auth.authenticationProvider(keycloakAuthenticationProvider);
}
sessionAuthenticationStrategy metodu
Açıklaması şöyle
Defines the session authentication strategy.
Şöyle yaparız
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
  return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
KeycloakConfigResolver Sınıfı
Açıklaması şöyle
By Default, the Spring Security Adapter looks for a keycloak.json configuration file. You can make sure it looks at the configuration provided by the Spring Boot Adapter by adding this bean
Şöyle yaparız
@Bean
public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
  return new KeycloakSpringBootConfigResolver();
}
configure metodu
Hangi adrese hangi rolün erişeceğini belirtiriz.

Örnek
Şöyle yaparız
@Value("${custom.keycloak.role}")
String keyCloakRole;

@Override
protected void configure(HttpSecurity http) throws Exception {
  super.configure(http);
  http.authorizeRequests()
    .anyRequest()
    .hasRole(keyCloakRole)
    .and()
      .exceptionHandling()
      .accessDeniedPage("/?denied")
    .and()
      .cors()
    .and()
      .csrf()
       .disable();
}
ayarlar işe şöyledir
custom.keycloak.role: test-user
keycloak:
    enable-basic-auth: true
    auth-server-url: http://localhost:8083/auth
    realm: master
    resource: test-clinet
    credentials:
        secret: 0e00874a-d6c3-426c-9704-43b88ecd448a
    ssl-required: external
    verify-token-audience: false
    use-resource-role-mappings: true
    principal-attribute: preferred_username
Örnek
Açıklaması şöyle
Rather than using @RolesAllowed annotation, the same configuration can be made in KeycloakSecurityConfig class as below.
Şöyle yaparız
@Override
protected void configure(HttpSecurity http) throws Exception {
  super.configure(http);
  http.authorizeRequests()
    .antMatchers("/test/anonymous").permitAll()
    .antMatchers("/test/user").hasAnyRole("user")
    .antMatchers("/test/admin").hasAnyRole("admin")
    .antMatchers("/test/all-user").hasAnyRole("user","admin")
    .anyRequest()
    .permitAll();
  http.csrf().disable();
}
Ayarlar
Örnek
Şöyle yaparız
server.port                         = 8000alo

keycloak.realm                      = Demo-Realm
keycloak.auth-server-url            = http://localhost:8080/auth
keycloak.ssl-required               = external
keycloak.resource                   = springboot-microservice
keycloak.credentials.secret         = XXXXXXXXXXXXXXXXXXXXXXXXX
keycloak.use-resource-role-mappings = true
keycloak.bearer-only                = true