Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ public ResponseEntity<BaseResponse<CertificateIssueResponse>> issueCertificate(
@Valid @RequestBody CertificateIssueRequest certificateIssueRequest,
HttpServletRequest request
) {
log.info("인증서 발급 요청 - 전화번호: {}", certificateIssueRequest.phoneNo());
String ipAddress = request.getRemoteAddr();
String userAgent = request.getHeader(USER_AGENT);
return ApiResponseUtil.success(SuccessCode.OK, certificateService.issueCertificate(certificateIssueRequest, ipAddress, userAgent));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,13 @@
public record CertificateIssueResponse(
String serialNumber,
LocalDateTime issuedAt,
LocalDateTime expiresAt,
String publicKey
LocalDateTime expiresAt
) {
public static CertificateIssueResponse from(Certificate certificate) {
return CertificateIssueResponse.builder()
.serialNumber(certificate.getSerialNumber())
.issuedAt(certificate.getIssuedAt())
.expiresAt(certificate.getExpiresAt())
.publicKey(certificate.getPublicKey())
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

@Repository
Expand All @@ -18,11 +16,7 @@ public interface CertificateRepository extends JpaRepository<Certificate, Long>
@Query("SELECT ctf FROM Certificate ctf JOIN FETCH ctf.user WHERE ctf.serialNumber = :serial")
Optional<Certificate> findBySerialNumber(@Param("serial") String serialNumber);

List<Certificate> findByUser(User user);

Optional<Certificate> findByUserAndStatus(User user, CertificateStatus status);

long countByUserAndStatus(User user, CertificateStatus status);

boolean existsCertificateByStatusAndUser(CertificateStatus status, User user);
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,9 @@
package org.creditto.authserver.certificate.repository;

import org.creditto.authserver.certificate.entity.Certificate;
import org.creditto.authserver.certificate.entity.CertificateUsageHistory;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.time.LocalDateTime;
import java.util.List;

@Repository
public interface CertificateUsageHistoryRepository extends JpaRepository<CertificateUsageHistory, Long> {

List<CertificateUsageHistory> findByCertificateIdOrderByCreatedAtDesc(Long certificateId);

List<CertificateUsageHistory> findByCertificateIdAndSuccessFalseAndCreatedAtAfter(
Long certificateId,
LocalDateTime after
);

List<CertificateUsageHistory> findByCertificate_User_IdOrderByCreatedAtDesc(Long userId);

List<CertificateUsageHistory> findByCertificate(Certificate certificate);
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import java.security.PrivateKey;
import java.security.PublicKey;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.UUID;

Expand Down Expand Up @@ -158,125 +157,6 @@ public Map<String, String> getSerialNumberByUser(CertificateSerialRequest certif
return Map.of(CERTIFICATE_SERIAL, certificate.getSerialNumber());
}


public List<CertificateUsageHistory> getCertificateHistory(String serialNumber, String simplePassword) {
Certificate certificate = getCertificateBySerialNumber(serialNumber);
try {
if (verifyCertificateKeyPair(simplePassword, certificate)) {
recordUsageHistory(certificate, HistoryAction.READ, true, null, "", "");
return certificateUsageHistoryRepository.findByCertificate(certificate);
} else {
recordUsageHistory(certificate, HistoryAction.READ, false, null, "", "");
throw new InvalidSimplePasswordException(CERTIFICATE_AUTH_FAILED);
}
} catch (GeneralSecurityException e) {
throw new InvalidSimplePasswordException(CERTIFICATE_AUTH_FAILED);
}
}

/**
* 사용자 인증서 목록 조회
*/
public List<Certificate> getUserCertificates(Long userId) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new EntityNotFoundException(USER_NOT_FOUND));

return certificateRepository.findByUser(user);
}

/**
* 활성 인증서 목록 조회
*/
public Certificate getActiveCertificates(Long userId) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new EntityNotFoundException(USER_NOT_FOUND));

return certificateRepository.findByUserAndStatus(user, CertificateStatus.ACTIVE)
.orElseThrow(() -> new CertificateNotFoundException(CERTIFICATE_NOT_FOUND));
}

/**
* 인증서 폐기
*/
@Transactional
public void revokeCertificate(String serialNumber, String simplePassword, String reason) {
Certificate certificate = getCertificateBySerialNumber(serialNumber);
try {
if (verifyCertificateKeyPair(simplePassword, certificate)) {
certificate.revoke(reason);
certificateRepository.save(certificate);
log.info("인증서 폐기 완료 - 일련번호: {}, 사유: {}", serialNumber, reason);
} else {
throw new InvalidSimplePasswordException(CERTIFICATE_AUTH_FAILED);
}
} catch (GeneralSecurityException e) {
throw new InvalidSimplePasswordException(CERTIFICATE_AUTH_FAILED);
}
}

/**
* 인증서 상세 조회
*/
public Certificate getCertificate(String serialNumber, String simplePassword) {
Certificate certificate = getCertificateBySerialNumber(serialNumber);
try {
if (verifyCertificateKeyPair(simplePassword, certificate)) {
return certificate;
} else {
throw new InvalidSimplePasswordException(CERTIFICATE_AUTH_FAILED);
}
} catch (GeneralSecurityException e) {
throw new InvalidSimplePasswordException(CERTIFICATE_AUTH_FAILED);
}
}

/**
* 활성 인증서 개수 조회
*/
public long countActiveCertificates(Long userId) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new EntityNotFoundException(USER_NOT_FOUND));

return certificateRepository.countByUserAndStatus(user, CertificateStatus.ACTIVE);
}

/**
* 인증서 갱신
*/
@Transactional
public CertificateIssueResponse renewCertificate(String oldSerialNumber, String simplePassword) {
// 기존 인증서 조회 및 검증
Certificate oldCertificate = getCertificateBySerialNumber(oldSerialNumber);

User user = oldCertificate.getUser();

// 새 RSA 키 쌍 생성
KeyPair keyPair = encryptionUtil.generateRSAKeyPair();

// 새 인증서별 SALT 생성
String certificateSalt = AESUtil.generateSalt();

// 개인키를 간편비밀번호로 암호화
String encryptedPrivateKey = encryptionUtil.encryptPrivateKey(
keyPair.getPrivate(),
simplePassword,
certificateSalt
);

Certificate newCertificate = createCertificate(keyPair, user, encryptedPrivateKey, certificateSalt);

certificateRepository.save(newCertificate);

// 기존 인증서 폐기
oldCertificate.revoke("인증서 갱신");
certificateRepository.save(oldCertificate);

log.info("인증서 갱신 완료 - 사용자: {}, 기존: {}, 신규: {}",
user.getName(), oldSerialNumber, newCertificate.getSerialNumber());

return CertificateIssueResponse.from(newCertificate);
}

private Certificate createCertificate(KeyPair keyPair, User user, String encryptedPrivateKey, String certificateSalt) {
String publicKey = encryptionUtil.encodePublicKey(keyPair.getPublic());

Expand Down