Spring

Spring Boot 인증 감사 지원

기록만이살길 2022. 12. 19. 22:14
반응형

1. 개요

이 짧은 기사에서는 Spring Security와 함께 Spring Boot Actuator 모듈과 인증 및 권한 부여 이벤트 게시 지원에 대해 살펴보겠습니다.

2. 메이븐 의존성

먼저 pom.xml 에 spring-boot-starter-actuator 를 추가해야 합니다.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    <version>2.7.2</version>
</dependency>

최신 버전은 Maven Central 리포지토리에서 사용할 수 있습니다.

3. 인증 및 권한 부여 이벤트 수신

Spring Boot 애플리케이션에서 모든 인증 및 권한 부여 시도를 기록하려면 수신기 메서드로 빈을 정의하면 됩니다.

@Component
public class LoginAttemptsLogger {

    @EventListener
    public void auditEventHappened(
      AuditApplicationEvent auditApplicationEvent) {
        
        AuditEvent auditEvent = auditApplicationEvent.getAuditEvent();
        System.out.println("Principal " + auditEvent.getPrincipal() 
          + " - " + auditEvent.getType());

        WebAuthenticationDetails details = 
          (WebAuthenticationDetails) auditEvent.getData().get("details");
        System.out.println("Remote IP address: " 
          + details.getRemoteAddress());
        System.out.println("  Session Id: " + details.getSessionId());
    }
}

사용 가능한 정보를 표시하기 위해 AuditApplicationEvent 에서 사용할 수 있는 항목 중 일부를 출력하고 있다는 점에 유의 하십시오. 실제 애플리케이션에서는 해당 정보를 추가로 처리하기 위해 리포지토리 또는 캐시에 저장하려고 할 수 있습니다.

모든 Spring bean이 작동합니다. 새로운 Spring 이벤트 지원의 기본은 매우 간단합니다.

  • 메서드에 @EventListener 어노테이션을 추가합니다.
  • 메서드의 유일한 인수로 AuditApplicationEvent 를 추가합니다.

애플리케이션 실행 결과는 다음과 같습니다.

Principal anonymousUser - AUTHORIZATION_FAILURE
  Remote IP address: 0:0:0:0:0:0:0:1
  Session Id: null
Principal user - AUTHENTICATION_FAILURE
  Remote IP address: 0:0:0:0:0:0:0:1
  Session Id: BD41692232875A5A65C5E35E63D784F6
Principal user - AUTHENTICATION_SUCCESS
  Remote IP address: 0:0:0:0:0:0:0:1
  Session Id: BD41692232875A5A65C5E35E63D784F6

이 예에서는 리스너가 세 개의 AuditApplicationEvent 를 수신했습니다.

  1. 로그인하지 않고 제한된 페이지에 대한 액세스를 요청했습니다.
  2. 로그온하는 동안 잘못된 암호가 사용되었습니다.
  3. 두 번째로 올바른 비밀번호를 사용했습니다.

4. 인증 감사 수신기

Spring Boot의 AuthorizationAuditListener 에 의해 노출된 정보 가 충분하지 않은 경우 더 많은 정보를 노출하기 위해 고유한 bean을 생성할 수 있습니다.

권한 부여에 실패했을 때 액세스된 요청 URL도 노출하는 예를 살펴보겠습니다.

@Component
public class ExposeAttemptedPathAuthorizationAuditListener 
  extends AbstractAuthorizationAuditListener {

    public static final String AUTHORIZATION_FAILURE 
      = "AUTHORIZATION_FAILURE";

    @Override
    public void onApplicationEvent(AbstractAuthorizationEvent event) {
        if (event instanceof AuthorizationFailureEvent) {
            onAuthorizationFailureEvent((AuthorizationFailureEvent) event);
        }
    }

    private void onAuthorizationFailureEvent(
      AuthorizationFailureEvent event) {
        Map<String, Object> data = new HashMap<>();
        data.put(
          "type", event.getAccessDeniedException().getClass().getName());
        data.put("message", event.getAccessDeniedException().getMessage());
        data.put(
          "requestUrl", ((FilterInvocation)event.getSource()).getRequestUrl() );
        
        if (event.getAuthentication().getDetails() != null) {
            data.put("details", 
              event.getAuthentication().getDetails());
        }
        publish(new AuditEvent(event.getAuthentication().getName(), 
          AUTHORIZATION_FAILURE, data));
    }
}

이제 리스너에 요청 URL을 기록할 수 있습니다.

@Component
public class LoginAttemptsLogger {

    @EventListener
    public void auditEventHappened(
      AuditApplicationEvent auditApplicationEvent) {
        AuditEvent auditEvent = auditApplicationEvent.getAuditEvent();
 
        System.out.println("Principal " + auditEvent.getPrincipal() 
          + " - " + auditEvent.getType());

        WebAuthenticationDetails details
          = (WebAuthenticationDetails) auditEvent.getData().get("details");
 
        System.out.println("  Remote IP address: " 
          + details.getRemoteAddress());
        System.out.println("  Session Id: " + details.getSessionId());
        System.out.println("  Request URL: " 
          + auditEvent.getData().get("requestUrl"));
    }
}

결과적으로 이제 출력에 요청된 URL이 포함됩니다.

Principal anonymousUser - AUTHORIZATION_FAILURE
  Remote IP address: 0:0:0:0:0:0:0:1
  Session Id: null
  Request URL: /hello

이 예제에서는 추상 AbstractAuthorizationAuditListener 에서 확장 했으므로 구현에서 해당 기본 클래스 의 게시 메서드를 사용할 수 있습니다.

테스트하려면 소스 코드를 확인하고 다음을 실행하십시오.

mvn clean spring-boot:run

그런 다음 브라우저에서 http://localhost:8080/ 을 가리킬 수 있습니다 .

5. 감사 이벤트 저장

기본적으로 Spring Boot는 AuditEventRepository 에 감사 이벤트를 저장합니다 . 자체 구현으로 빈을 생성하지 않으면 InMemoryAuditEventRepository 가 자동으로 연결됩니다.

InMemoryAuditEventRepository최근 4000개의 감사 이벤트를 메모리에 저장하는 일종의 순환 버퍼입니다. 그런 다음 이러한 이벤트는 관리 엔드포인트 http://localhost:8080/auditevents 를 통해 액세스할 수 있습니다 .

그러면 감사 이벤트의 JSON 표현이 반환됩니다.

{
  "events": [
    {
      "timestamp": "2017-03-09T19:21:59+0000",
      "principal": "anonymousUser",
      "type": "AUTHORIZATION_FAILURE",
      "data": {
        "requestUrl": "/auditevents",
        "details": {
          "remoteAddress": "0:0:0:0:0:0:0:1",
          "sessionId": null
        },
        "type": "org.springframework.security.access.AccessDeniedException",
        "message": "Access is denied"
      }
    },
    {
      "timestamp": "2017-03-09T19:22:00+0000",
      "principal": "anonymousUser",
      "type": "AUTHORIZATION_FAILURE",
      "data": {
        "requestUrl": "/favicon.ico",
        "details": {
          "remoteAddress": "0:0:0:0:0:0:0:1",
          "sessionId": "18FA15865F80760521BBB736D3036901"
        },
        "type": "org.springframework.security.access.AccessDeniedException",
        "message": "Access is denied"
      }
    },
    {
      "timestamp": "2017-03-09T19:22:03+0000",
      "principal": "user",
      "type": "AUTHENTICATION_SUCCESS",
      "data": {
        "details": {
          "remoteAddress": "0:0:0:0:0:0:0:1",
          "sessionId": "18FA15865F80760521BBB736D3036901"
        }
      }
    }
  ]
}

6. 결론

Spring Boot의 액추에이터 지원을 통해 사용자의 인증 및 권한 부여 시도를 기록하는 것이 쉬워집니다. 판독기는 또한 몇 가지 추가 정보에 대해 프로덕션 준비 감사 를 참조합니다.

이 기사의 코드는 GitHub 에서 찾을 수 있습니다 .

Generic footer banner
참고
  • https://docs.spring.io/spring-framework/docs/current/reference/html
  • https://www.baeldung.com/spring-boot-authentication-audit
반응형