|
|
|
@@ -1,7 +1,20 @@
|
|
|
|
|
package com.eactive.eai.rms.ext.kjb.sso;
|
|
|
|
|
|
|
|
|
|
import com.eactive.apim.portal.user.entity.UserInfo;
|
|
|
|
|
import com.eactive.eai.common.seed.Seed;
|
|
|
|
|
import com.eactive.eai.rms.common.context.MonitoringContext;
|
|
|
|
|
import com.eactive.eai.rms.common.datasource.DataSourceType;
|
|
|
|
|
import com.eactive.eai.rms.common.datasource.DataSourceTypeManager;
|
|
|
|
|
import com.eactive.eai.rms.common.interceptor.InterceptorSkipController;
|
|
|
|
|
import com.eactive.eai.rms.common.login.MainController;
|
|
|
|
|
import com.eactive.eai.rms.common.util.CommonConstants;
|
|
|
|
|
import com.eactive.eai.rms.data.entity.man.monitoringProperty.service.MonitoringPropertyService;
|
|
|
|
|
import com.eactive.eai.rms.data.entity.man.user.UserInfoService;
|
|
|
|
|
import com.eactive.eai.rms.data.entity.man.user.UserRole;
|
|
|
|
|
import com.eactive.eai.rms.data.entity.man.user.UserRoleId;
|
|
|
|
|
import com.eactive.eai.rms.data.entity.man.user.UserRoleService;
|
|
|
|
|
import com.eactive.eai.rms.data.entity.man.user.UserServiceTypeService;
|
|
|
|
|
import com.eactive.eai.rms.onl.apim.masking.MaskingUtils;
|
|
|
|
|
import com.eactive.ext.kjb.common.KjbProperty;
|
|
|
|
|
import com.eactive.ext.kjb.sso.KjbSsoModule;
|
|
|
|
|
import com.eactive.ext.kjb.util.KjbPropertyInjector;
|
|
|
|
@@ -14,6 +27,8 @@ import org.springframework.web.bind.annotation.RequestParam;
|
|
|
|
|
import javax.servlet.http.Cookie;
|
|
|
|
|
import javax.servlet.http.HttpServletRequest;
|
|
|
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
|
|
import javax.servlet.http.HttpSession;
|
|
|
|
|
import java.util.Optional;
|
|
|
|
|
import java.util.Properties;
|
|
|
|
|
|
|
|
|
|
@Slf4j
|
|
|
|
@@ -23,36 +38,49 @@ public class SsoController implements InterceptorSkipController {
|
|
|
|
|
|
|
|
|
|
private final KjbSsoModule ssoModule;
|
|
|
|
|
private final KjbProperty prop;
|
|
|
|
|
private final UserInfoService userInfoService;
|
|
|
|
|
private final UserRoleService userRoleService;
|
|
|
|
|
private final UserServiceTypeService userServiceTypeService;
|
|
|
|
|
private final MonitoringContext monitoringContext;
|
|
|
|
|
private final MainController mainController;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public SsoController(MonitoringPropertyService monitoringPropertyService) {
|
|
|
|
|
public SsoController(MonitoringPropertyService monitoringPropertyService,
|
|
|
|
|
UserInfoService userInfoService,
|
|
|
|
|
UserRoleService userRoleService,
|
|
|
|
|
UserServiceTypeService userServiceTypeService,
|
|
|
|
|
MonitoringContext monitoringContext,
|
|
|
|
|
MainController mainController) {
|
|
|
|
|
KjbPropertyInjector kjbPropertyInjector = new KjbPropertyInjector(monitoringPropertyService, PROP_GORUP_ID);
|
|
|
|
|
prop = kjbPropertyInjector.inject(new KjbProperty());
|
|
|
|
|
this.ssoModule = KjbSsoModule.getInstance(prop);
|
|
|
|
|
this.userInfoService = userInfoService;
|
|
|
|
|
this.userRoleService = userRoleService;
|
|
|
|
|
this.userServiceTypeService = userServiceTypeService;
|
|
|
|
|
this.monitoringContext = monitoringContext;
|
|
|
|
|
this.mainController = mainController;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@RequestMapping(value = "/sso/login.do")
|
|
|
|
|
public String login(HttpServletRequest req, HttpServletResponse res,
|
|
|
|
|
@RequestParam(name = "UURL", required = false) String uurl) throws Exception {
|
|
|
|
|
@RequestParam(name = "UURL", required = false) String uurl) throws Exception {
|
|
|
|
|
HttpSession session = req.getSession();
|
|
|
|
|
String ssoId = ssoModule.getSsoId(req);
|
|
|
|
|
|
|
|
|
|
log.debug("ssoId : {}", ssoId);
|
|
|
|
|
log.debug("uurl : {}", uurl);
|
|
|
|
|
|
|
|
|
|
log.debug("KjbProperty : \n{}", prop.toJsonString(true));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 디버깅용 쿠키 목록 출력
|
|
|
|
|
Cookie[] cookies = req.getCookies();
|
|
|
|
|
if (cookies == null || cookies.length == 0) {
|
|
|
|
|
log.debug("No cookies");
|
|
|
|
|
} else {
|
|
|
|
|
for (Cookie c: cookies) {
|
|
|
|
|
log.debug("Cookie[{}] : {}, Domain={}, Path={}, Max-Age={}, Secure={}, Version={}",
|
|
|
|
|
c.getName(), c.getValue(), c.getDomain(), c.getPath(), c.getMaxAge(), c.getSecure(), c.getVersion());
|
|
|
|
|
if (log.isDebugEnabled()) {
|
|
|
|
|
Cookie[] cookies = req.getCookies();
|
|
|
|
|
if (cookies == null || cookies.length == 0) {
|
|
|
|
|
log.debug("No cookies");
|
|
|
|
|
} else {
|
|
|
|
|
for (Cookie c : cookies) {
|
|
|
|
|
log.debug("Cookie[{}] : Domain={}, Path={}",
|
|
|
|
|
c.getName(), c.getDomain(), c.getPath());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (StringUtils.isEmpty(uurl)) {
|
|
|
|
|
uurl = ssoModule.getAscpUrl();
|
|
|
|
@@ -62,45 +90,225 @@ public class SsoController implements InterceptorSkipController {
|
|
|
|
|
ssoModule.goLoginPage(res, uurl);
|
|
|
|
|
return null;
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
// EAM 세션 검증
|
|
|
|
|
String retCode = ssoModule.getEamSessionCheck(req, res);
|
|
|
|
|
log.debug("retCode : {}", retCode);
|
|
|
|
|
|
|
|
|
|
log.debug("Property - sso.ignore_validation = {}", prop.isSsoIgnoreValidation());
|
|
|
|
|
if (!prop.isSsoIgnoreValidation() && !"0".equalsIgnoreCase(retCode)) {
|
|
|
|
|
|
|
|
|
|
ssoModule.goErrorPage(res, Integer.parseInt(retCode));
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (StringUtils.isEmpty(ssoId)) {
|
|
|
|
|
throw new IllegalStateException("KJB-SSO - ssoId 획득 실패");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 기본 정보
|
|
|
|
|
Properties info = ssoModule.getUserInfos(ssoId);
|
|
|
|
|
if (info != null) {
|
|
|
|
|
log.debug("info - {}", info.keySet());
|
|
|
|
|
info.keySet().forEach( k -> {
|
|
|
|
|
log.debug("{} : {}", k, info.get(k));
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
log.debug("User info is null");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 확장 정보
|
|
|
|
|
Properties extendedInfo = ssoModule.getUserExFields(ssoId);
|
|
|
|
|
if (extendedInfo != null) {
|
|
|
|
|
log.debug("extendedInfo - {}", info.keySet());
|
|
|
|
|
extendedInfo.keySet().forEach( k -> {
|
|
|
|
|
log.debug("{} : {}", k, extendedInfo.get(k));
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
log.debug("User Extended info is null");
|
|
|
|
|
// SSO 검증 실패 시 에러 메시지 설정 및 로그인 페이지로 이동
|
|
|
|
|
session.setAttribute("resultMsg", "SSO 로그인을 실패 하였습니다. 다른 로그인 방식을 시도 하세요");
|
|
|
|
|
return "redirect:/loginForm.do";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return "redirect:/main.do";
|
|
|
|
|
if (StringUtils.isEmpty(ssoId)) {
|
|
|
|
|
session.setAttribute("resultMsg", "SSO 인증 정보를 획득하지 못했습니다.");
|
|
|
|
|
return "redirect:/loginForm.do";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 기본 정보
|
|
|
|
|
Properties info = ssoModule.getUserInfos(ssoId);
|
|
|
|
|
// 확장 정보
|
|
|
|
|
Properties extendedInfo = ssoModule.getUserExFields(ssoId);
|
|
|
|
|
|
|
|
|
|
// 필수 필드 검증
|
|
|
|
|
try {
|
|
|
|
|
validateRequiredFields(info, extendedInfo);
|
|
|
|
|
} catch (IllegalStateException e) {
|
|
|
|
|
log.warn("SSO 필수 필드 검증 실패: {}", e.getMessage());
|
|
|
|
|
session.setAttribute("resultMsg", e.getMessage());
|
|
|
|
|
return "redirect:/loginForm.do";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 사용자 정보 로깅 (개인정보 마스킹 처리)
|
|
|
|
|
String userId = info.getProperty("USERID");
|
|
|
|
|
String name = info.getProperty("NAME");
|
|
|
|
|
String email = info.getProperty("EMAIL");
|
|
|
|
|
String cellPhoneNo = extendedInfo != null ? extendedInfo.getProperty("CELLPHONENO") : null;
|
|
|
|
|
|
|
|
|
|
log.info("SSO 로그인 시도 - userId: {}", userId);
|
|
|
|
|
log.debug("SSO 사용자 정보 - userId: {}, name: {}, phone: {}, email: {}",
|
|
|
|
|
userId,
|
|
|
|
|
MaskingUtils.maskName(name),
|
|
|
|
|
maskPhoneNumber(cellPhoneNo),
|
|
|
|
|
maskEmail(email));
|
|
|
|
|
|
|
|
|
|
// 사용자 생성 또는 업데이트
|
|
|
|
|
UserInfo userInfo = findOrCreateUser(info, extendedInfo);
|
|
|
|
|
|
|
|
|
|
// 로그인 세션 설정 (MainController 위임)
|
|
|
|
|
log.info("SSO 로그인 성공 - userId: {}", userId);
|
|
|
|
|
return mainController.setupSsoLoginSession(req, userInfo);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 필수 필드 검증
|
|
|
|
|
*/
|
|
|
|
|
private void validateRequiredFields(Properties info, Properties extendedInfo) throws IllegalStateException {
|
|
|
|
|
validateField(info, "USERID", "사용자ID");
|
|
|
|
|
validateField(info, "NAME", "사용자명");
|
|
|
|
|
validateField(extendedInfo, "CELLPHONENO", "휴대폰번호");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void validateField(Properties props, String key, String fieldName) {
|
|
|
|
|
String value = props != null ? props.getProperty(key) : null;
|
|
|
|
|
if (StringUtils.isEmpty(value)) {
|
|
|
|
|
throw new IllegalStateException(fieldName + " - SSO 서버로 부터 전달 받지 못했습니다.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 사용자 조회 또는 생성
|
|
|
|
|
*/
|
|
|
|
|
private UserInfo findOrCreateUser(Properties info, Properties extendedInfo) throws Exception {
|
|
|
|
|
String userId = info.getProperty("USERID");
|
|
|
|
|
|
|
|
|
|
// 대소문자 구분 없이 검색
|
|
|
|
|
Optional<UserInfo> existingUser = userInfoService.findByUserIdIgnoreCase(userId);
|
|
|
|
|
|
|
|
|
|
if (existingUser.isPresent()) {
|
|
|
|
|
return updateUserIfNeeded(existingUser.get(), info, extendedInfo);
|
|
|
|
|
} else {
|
|
|
|
|
return createNewUser(info, extendedInfo);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 신규 사용자 생성
|
|
|
|
|
*/
|
|
|
|
|
private UserInfo createNewUser(Properties info, Properties extendedInfo) throws Exception {
|
|
|
|
|
String userId = info.getProperty("USERID");
|
|
|
|
|
String name = info.getProperty("NAME");
|
|
|
|
|
String email = info.getProperty("EMAIL");
|
|
|
|
|
String cellPhoneNo = extendedInfo != null ? extendedInfo.getProperty("CELLPHONENO") : null;
|
|
|
|
|
String positionName = extendedInfo != null ? extendedInfo.getProperty("LEGACYPOSITIONNAME") : null;
|
|
|
|
|
String deptName = extendedInfo != null ? extendedInfo.getProperty("LEGACYDEPTNAME") : null;
|
|
|
|
|
|
|
|
|
|
UserInfo userInfo = new UserInfo();
|
|
|
|
|
userInfo.setUserid(userId);
|
|
|
|
|
userInfo.setUsername(name);
|
|
|
|
|
userInfo.setPassword(Seed.encrypt("!" + userId));
|
|
|
|
|
userInfo.setCphnno(cleanPhoneNumber(cellPhoneNo));
|
|
|
|
|
userInfo.setRoleidnfiname(CommonConstants.DEPT_DEVELOPER);
|
|
|
|
|
|
|
|
|
|
// 부가 필드 설정 (값이 있을 경우만)
|
|
|
|
|
if (StringUtils.isNotEmpty(email)) {
|
|
|
|
|
userInfo.setEmad(email);
|
|
|
|
|
}
|
|
|
|
|
if (StringUtils.isNotEmpty(positionName)) {
|
|
|
|
|
userInfo.setJobtlname(positionName);
|
|
|
|
|
}
|
|
|
|
|
if (StringUtils.isNotEmpty(deptName)) {
|
|
|
|
|
userInfo.setDvsnname(deptName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
userInfoService.save(userInfo);
|
|
|
|
|
|
|
|
|
|
// 기본 역할 할당
|
|
|
|
|
String roleId = monitoringContext.getStringProperty(
|
|
|
|
|
MonitoringContext.USER_DEFAULT_RULE, "newbie");
|
|
|
|
|
UserRole userRole = new UserRole();
|
|
|
|
|
userRole.setId(new UserRoleId(userId, roleId));
|
|
|
|
|
userRoleService.save(userRole);
|
|
|
|
|
|
|
|
|
|
// 서비스 타입 할당
|
|
|
|
|
DataSourceTypeManager.getDynamicDataSourceTypes().stream()
|
|
|
|
|
.map(DataSourceType::getName)
|
|
|
|
|
.forEach(type -> userServiceTypeService.insertUserServiceType(userId, type));
|
|
|
|
|
|
|
|
|
|
log.info("SSO 신규 사용자 생성 완료 - userId: {}", userId);
|
|
|
|
|
return userInfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 기존 사용자 정보 업데이트 (변경된 필드만)
|
|
|
|
|
*/
|
|
|
|
|
private UserInfo updateUserIfNeeded(UserInfo userInfo, Properties info, Properties extendedInfo) {
|
|
|
|
|
boolean updated = false;
|
|
|
|
|
String userId = userInfo.getUserid();
|
|
|
|
|
|
|
|
|
|
String name = info.getProperty("NAME");
|
|
|
|
|
String email = info.getProperty("EMAIL");
|
|
|
|
|
String cellPhoneNo = extendedInfo != null ? extendedInfo.getProperty("CELLPHONENO") : null;
|
|
|
|
|
String positionName = extendedInfo != null ? extendedInfo.getProperty("LEGACYPOSITIONNAME") : null;
|
|
|
|
|
String deptName = extendedInfo != null ? extendedInfo.getProperty("LEGACYDEPTNAME") : null;
|
|
|
|
|
|
|
|
|
|
// 사용자명 업데이트
|
|
|
|
|
if (StringUtils.isNotEmpty(name) && !name.equals(userInfo.getUsername())) {
|
|
|
|
|
userInfo.setUsername(name);
|
|
|
|
|
updated = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 휴대폰번호 업데이트
|
|
|
|
|
String cleanedPhone = cleanPhoneNumber(cellPhoneNo);
|
|
|
|
|
if (StringUtils.isNotEmpty(cleanedPhone) && !cleanedPhone.equals(userInfo.getCphnno())) {
|
|
|
|
|
userInfo.setCphnno(cleanedPhone);
|
|
|
|
|
updated = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 이메일 업데이트
|
|
|
|
|
if (StringUtils.isNotEmpty(email) && !email.equals(userInfo.getEmad())) {
|
|
|
|
|
userInfo.setEmad(email);
|
|
|
|
|
updated = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 직위명 업데이트
|
|
|
|
|
if (StringUtils.isNotEmpty(positionName) && !positionName.equals(userInfo.getJobtlname())) {
|
|
|
|
|
userInfo.setJobtlname(positionName);
|
|
|
|
|
updated = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 부서명 업데이트
|
|
|
|
|
if (StringUtils.isNotEmpty(deptName) && !deptName.equals(userInfo.getDvsnname())) {
|
|
|
|
|
userInfo.setDvsnname(deptName);
|
|
|
|
|
updated = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (updated) {
|
|
|
|
|
userInfoService.save(userInfo);
|
|
|
|
|
log.info("SSO 사용자 정보 업데이트 완료 - userId: {}", userId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return userInfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 휴대폰번호에서 숫자만 추출
|
|
|
|
|
*/
|
|
|
|
|
private String cleanPhoneNumber(String phone) {
|
|
|
|
|
if (StringUtils.isEmpty(phone)) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
return phone.replaceAll("[^0-9]", "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 휴대폰번호 마스킹 (로그용)
|
|
|
|
|
*/
|
|
|
|
|
private String maskPhoneNumber(String phone) {
|
|
|
|
|
if (StringUtils.isEmpty(phone) || phone.length() < 4) {
|
|
|
|
|
return "****";
|
|
|
|
|
}
|
|
|
|
|
// 010-1234-5678 → 010-****-5678
|
|
|
|
|
String cleaned = phone.replaceAll("[^0-9]", "");
|
|
|
|
|
if (cleaned.length() < 7) {
|
|
|
|
|
return "****";
|
|
|
|
|
}
|
|
|
|
|
return cleaned.substring(0, 3) + "****" + cleaned.substring(cleaned.length() - 4);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 이메일 마스킹 (로그용)
|
|
|
|
|
*/
|
|
|
|
|
private String maskEmail(String email) {
|
|
|
|
|
if (StringUtils.isEmpty(email) || !email.contains("@")) {
|
|
|
|
|
return "****";
|
|
|
|
|
}
|
|
|
|
|
int atIndex = email.indexOf("@");
|
|
|
|
|
if (atIndex <= 2) {
|
|
|
|
|
return "**" + email.substring(atIndex);
|
|
|
|
|
}
|
|
|
|
|
return email.substring(0, 2) + "**" + email.substring(atIndex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|