기존에 전자정부 프레임워크 3.6로 개발된 프로젝트를 4.2로 업데이트 하면서 스프링 부트로 변환하는 작업을 진행하면서 생긴 오류들과 디버깅 과정, 해결과정에 대한 회고입니다.
기존에 한 서버에 여러 프로젝트를 올리면서 리소스 분석 시 각 프로젝트별 분석이 어려웠다. 그래서 spring-boot-actuator 를 이용하여 프로젝트별 리소스 사용량을 분석하기 위해 egov 4.2 로 업데이트를 진행하였다.
# 버전 변경
기존
* spring.maven.artifact.version = 4.1.2 RELEASE
* egovframework.rte.version = 3.6.0
변경
* spring.maven.artifact.version = 5.3.27
* egovframework.rte.version = 4.2.0
# 디렉토리 구조 및 config 변경
기존에 src/main/resource 디렉토리 아래에 context-*.xml 로 빈 관리를 진행했다. 이 부분은 버전에 맞추어 수정을 계속해야하다보니 한번에 바꾸기에는 겁이 많았기에 우선 @SpringBootApplicaiton 어노테이션이 달린 메인 클래스에 @ImportResource("classpath:context-.*xml") 을 등록하여 변환을 완료했다.
또한 이 과정에서 전자정부프레임워크 관련 라이브러리들의 경로 변경이 있는데 egovframework.rte.fdl.~ 을 org.egovframe.rte.fdl.~ 로 변경해주면 된다. 더 자세한건 공식 홈페이지, 위키를 참고하면 좋습니다.
사실 이렇게 했을 때 프로젝트 빌드 및 실행은 완료된다.
하지만 실행만 될 뿐 기능이 정상적으로 동작하진 않는다.
※ egov security 간소화 공식 위키 - https://www.egovframe.go.kr/wiki/doku.php?id=egovframework:rte4.2:fdl:server_security:xmlschema
# 시큐리티 로그인 문제 ("/j_spirng_security_check" not found)
먼저 로그인과 관련해서 문제가 발생했다. 로그인 시도 시 기존에는 잘 되던게 갑자기 "/j_spirng_security_check" 와 관련된 페이지를 찾을 수 없다면서 에러 페이지를 반환했다. 구글링 결과 스프링 시큐리티 3버전 까지는 기본 url이 "/j_spirng_security_check" 이었으며, 파라미터들 또한 "j_username", "j_password" 라고 한다. 프로젝트 버전이 바뀌면서 스프링 시큐리티버전도 함께 바뀌다보니 따로 설정이 되어있지 않아 기본값을 따라 설정이 변경되어 에러가 발생한 것이었다. 로그인과 관련된 404 페이지 문제는 로그인을 요청할 때 post url을 "/login" 으로 변경해주면 된다.
요약
- 로그인 요청이 /j_spirng_security_check 로 되어있어 404 not found에러가 발생
- 스프링 시큐리티 버전이 바뀌면서 기본 url이 /j_spirng_security_check 에서 /login으로 변경됨
- 로그인 요청 url을 /login으로 변경하여 해결
# 시큐리티 로그인 문제 (로그인 불가)
그 다음으로 로그인 요청은 정상적으로 동작하는데 내부적으로 인증 처리에서 문제가 발생했다. 시큐리티와 관련된 설정은 전자정부 시큐리티 간소화 기능을 이용하여 context-security.xml로 관리중이었고
<egov-security:config id="securityConfig"
loginUrl="/security/login.do"
logoutSuccessUrl="/"
loginFailureUrl="/security/login.do?error=1"
accessDeniedUrl="/security/accessDenied.do"
defaultTargetUrl="/security/loginSuccess.do"
dataSource="dataSource"
jdbcUsersByUsernameQuery="..."
... />
내용은 위와 같다. (관련된 자세한 내용은 공식 위키를 참고해주세요.)
여기서 jdbcUsersByUsernameQuery 의 쿼리 부분에 user_id로 정보를 조회하여 데이터를 얻어오는데 user_id에 빈값 ("") 이 넘어가는 현상이 발생했다. user_id가 빈값이기에 정보를 찾지 못했고 로그인 처리가 안되었던 것이다. 이 부분과 관련해서 공식 faq를 찾아봤는데 일단 도움이 되는 답변은 찾지 못했다. 결론부터 말하면 전자정부 시큐리티 라이브러리에서 org.egovframe.rte.fdl.security.userdetails.jdbc 패키지의 loadUsersByUsername(String username) 매서드에서부터 문제가 발생했다. (어쩌다 해당 라이브러리까지 디버깅을 하게되었는지 정확히 기억나지 않아서 설명하지 못한게 아쉽다.) loadUsersByUsername(String username) 매서드에서 username이 빈값("")으로 넘어왔기에 데이터 조회에 문제가 발생하고 있었다. 그럼 이 매서드를 언제 사용하는지를 생각해봤을 때 로그인을 시도하는 과정에서 id, password가 폼 액션으로 요청되고 아이디를 통해 정보를 조회할 때 매서드가 사용된다는 것을 떠올렸다. 그래서 로그인과 관련된 폼의 input name을 username, password로 변경한 뒤 재시도했지만 똑같이 빈값이 들어왔다.
다음으로는 그럼 기본값으로 받지 못했다면 어디선가 파라미터 이름이 변경되었을 거라고 생각했다. 그래서 공식 문서와 egov관련 라이브러리들을 최대한 찾아봤지만 파라미터명을 변경하는 코드를 찾을 수 없었다. 마지막으로 로그인이 요청되는 시점부터 디버깅을 시작하였다. 폼을 이용한 로그인 자체는 스프링 시큐리티의 기능을 이용하였기에 UsernamePasswordAuthenticationFilter 구현체에서 디버깅을 시작하였다. username 을 인식하지 못하는 버그였기에 obtainUsername(HttpServletRequest request) 매서드에 포인트를 잡고 디버깅을 한 결과 원인을 알게되었다. 바로 usernameParameter가 기본값인 username이 아니라 egov_security_username 으로 되어있어서 제대로 읽어오지 못한 것이었다. 이와 관련된 내용은 내가 못 찾은걸 수도 있겠지만, 블로그나 공식문서에서 전혀 보지못한 파라미터명이었다. 파라미터명을 확인한 후 로그인 폼에서 파라미터명을 각각 "egov_security_username", "egov_security_password"로 변경한 뒤 로그인을 시도하니 정상적으로 로그인이 완료되었다.
요약
- egov-security 간소화 기능을 사용하면서 jdbcUsersByUsernameQuery 의 파라미터에 빈값("")이 들어가는 현상 발생
- 로그인 시 스프링시큐리티 폼 로그인을 이용하고 있기에 UsernamePasswordAuthenticationFilter 를 디버깅한 결과 usernameParameter, passwordParameter가 기본값이 아니라 egov_security_username, egov_security_password로 설정되어 있는 것을 발견
- 로그인 폼의 파라미터명을 변경 후 로그인 성공
# 시큐리티 로그인 문제 (권한 문제)
로그인 후 권한과 관련된 에러가 발생했다. url별로 접근 권한이 다르게 설정되어있는데 ADMIN 권한의 계정은 모든 곳에 접근 가능하게 설정되어있다. 그런데 특정 주소에서 접근 권한이 없다는 에러페이지가 뜨는 현상이 발생했다. url별 접근 권한 확인에 있어서 가장먼저 요청 url이 어디인지를 알아야한다고 생각했다. 실제로 @Controller 어노테이션을 사용한 클래스에 요청이 도달하기 전에 예외처리가 발생하기에 그보다 앞선 인터셉터 같은 곳에서 권한과 관련된 처리를 할 것이라고 예상했다. 가장 먼저 찾아본 곳은 egov-security 라이브러리였다. (일단 이번 오류의 대부분이 전자정부 프레임워크가 원인이었기에 유죄추정의 원칙으로 먼저 살펴보았다.) 실제로 org.egovframe.rte.fdl.security.intercept 패키지의 getAttributes(Object object) 매서드에서 요청에 대한 검사를 진행하고 있었다. (정확히는 그보다 먼저 다른 패키지의 beforeInvocation 매서드에서 진행되지만 요청 url에 대한 값을 검사하는 것은 getAttributes이기에 위와같이 작성했다.) 디버깅 결과 로그인한 유저에게 권한이 이상하게 들어가 있는 것을 확인했다. 프로젝트에서 사용되는 권한은 총 3개로 ROLE_ADMIN, ROLE_USER, ROLE_ANONYMOUS 이다. 여기서 ROLE_ADMIN 과 ROLE_ANONYMOUS 는 정상적으로 들어가는데 유저가
"ROLE_USER ROLE_USER"
와 같이 적용되어 있었다. 때문에 ROLE_USER가 접근가능한 페이지에서 .equals()가 false를 반환하여 접근이 거부되었던 것이다.
그럼 이 권한 설정은 어디서 이루어지는가 해서 찾아봤더니 context-security.xml에서
<egov-security:secured-object-config id="securedObjectConfig"
roleHierarchyString="
ROLE_ADMIN > ROLE_USER
ROLE_USER > ROLE_ANONYMOUS"
sqlRolesAndUrl="..."
... />
roleHierarchyString 에 정의된 권한별 레벨을 따라 설정이 되는 것을 확인했다. roleHierarchyString에 위와 같이 권한별 우선순위를 작성해주면 스프링 시큐리티 라이브러리의 org.springframework.security.access.hierarchicalroles 패키지에서 buildRolesReachableInOneStepMap 매서드를 통해 권한별 우선순위가 설정된다. roleHierarchyString의 문구를 엔터("\n")와 부등호(">")로 분리하여 설정이 진행되는데 문제가 roleHierarchyString에서 작성한 문구의 엔터가 인식이 안되는 오류가 발생해서 "ROLE_USER ROLE_USER" 과 같은 이상한 권한이 생성되었다. 처음에는 문구를 "ROLE_ADMIN > ROLE_USER \n ROLE_USER > ROLE_ANONYMOUS" 와 같이 "\n"을 인식할 수 있도록 수정해봤지만 이 때는 엔터로 인식하는것이 아니라 문자 그대로 "\n"로 인식해서 "ROLE_USER \n ROLE_USER" 과 같은 권한이 생성되었다. 이 부분은 아직 해결은 하지 못했다. 프로젝트에서 ANONYMOUS 권한을 가진 유저가 할 수 있는 기능이 없기에 임시적으로 "ROLE_ADMIN > ROLE_USER" 만 작성하여 에러를 해결하였다. 권한과 관련된 처리과정에서 부등호(">")를 여러번 작성하여 순위를 주는 것도 가능하다는 것을 알게되었다. 그러므로 "ROLE_ADMIN > ROLE_USER > ROLE_ANONYMOUS" 와 같이 작성했을 경우에 각각의 권한에 대한 우선순위가 생성되고 원하는 결과를 얻을 수 있었다.
요약
- url별 권한을 확인하는 과정에서 예상치 못한 권한이 인가되어 페이지 접근 권한이 불가한 현상 발생
- context-security.xml에서 작성한 roleHierarchyString 가 스프링 시큐리티 라이브러리의 hierarchicalroles 에서 권한별 우선순위를 설정하는 과정에서 엔터기호 ("\n")가 인식이 안되어 예상치 못한 권한이 생성됨
- 임시적으로 사용하지 않는 ANONYMOUS 를 제거하여 에러 해결
- 특별한 경우가 아닌 이상 부등호를 여러개 작성해서 해결가능하다. ( "ROLE_ADMIN > ROLE_USER > ROLE_ANONYMOUS")
만약 egov-security과 관련해서 로그인폼 사용 시 파라미터 변경과 관련된 문서, 블로그 를 아시는 분은 댓글 남겨주시면 매우 감사하겠습니다 (_ _)
- 2024-05-27 - 권한 문제 임시 처리 수정
'회고' 카테고리의 다른 글
20250104) 프로젝트에 대한 인수인계, 개발문서의 중요성을 깨달은 회고 (0) | 2025.01.04 |
---|---|
톰캣 war 파일 변경 시 자동 배포과 관련된 회고 (0) | 2024.10.08 |
20240321-회고(스프링 웹소켓 오류 회고 / 오류 해결완료 / 원인파악 중) (0) | 2024.03.21 |
20231208 회고 (0) | 2023.12.08 |
20231115 업무 회고 (0) | 2023.11.15 |