diff --git a/build.gradle b/build.gradle index 44208df4..5a9733fb 100644 --- a/build.gradle +++ b/build.gradle @@ -105,7 +105,14 @@ dependencies implementation 'org.apache.poi:poi-ooxml:4.1.2' implementation 'org.apache.poi:poi-scratchpad:4.1.2' implementation 'org.apache.poi:poi-examples:4.1.2' - + + // 2026.04.02 나혁제 구글 OTP 기능 추가 + implementation 'com.warrenstrange:googleauth:1.5.0' + + // 2026.04.02 나혁제 구글 OTP 기능 추가 + implementation 'com.google.zxing:core:3.5.1' + implementation 'com.google.zxing:javase:3.5.1' + implementation 'de.taimos:totp:1.0' } test diff --git a/src/main/java/com/urpsys/basefront/common/service/GoogleOtpService.java b/src/main/java/com/urpsys/basefront/common/service/GoogleOtpService.java new file mode 100644 index 00000000..3a0cf8fe --- /dev/null +++ b/src/main/java/com/urpsys/basefront/common/service/GoogleOtpService.java @@ -0,0 +1,92 @@ +package com.urpsys.basefront.common.service; + +import java.io.ByteArrayOutputStream; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.security.SecureRandom; +import java.util.Base64; + +import org.apache.commons.codec.binary.Base32; +import org.apache.commons.codec.binary.Hex; + +import com.google.zxing.BarcodeFormat; +import com.google.zxing.client.j2se.MatrixToImageWriter; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.qrcode.QRCodeWriter; +import com.warrenstrange.googleauth.GoogleAuthenticator; +import com.warrenstrange.googleauth.GoogleAuthenticatorKey; + +import de.taimos.totp.TOTP; + +public class GoogleOtpService +{ + /** + * 비밀키 생성. + * + * @return 32자리의 비밀키 + */ + public static String generateSecretKey() + { + SecureRandom random = new SecureRandom(); + byte[] bytes = new byte[20]; + random.nextBytes(bytes); + Base32 base32 = new Base32(); + return base32.encodeToString(bytes); + } + + /** + * QR코드 URL 생성. + * + * @param displayName 표시할 이름 + * @param secret 비밀키 + * @return QR코드 URL + */ + public static String getQrCodeUrl(String displayName, String secret) throws Exception + { + String format = "otpauth://totp/" + URLEncoder.encode(displayName, StandardCharsets.UTF_8) + .replace("+", "%20") + + "?secret=" + secret; + return generateQRCodeImage(format); + } + + /** + * QR코드 이미지 생성. + * + * @param barcodeText 바코드 텍스트 + * @return QR코드 이미지 + */ + public static String generateQRCodeImage(String barcodeText) throws Exception + { + QRCodeWriter qrCodeWriter = new QRCodeWriter(); + BitMatrix bitMatrix = qrCodeWriter.encode(barcodeText, BarcodeFormat.QR_CODE, 200, 200); + + ByteArrayOutputStream pngOutputStream = new ByteArrayOutputStream(); + + MatrixToImageWriter.writeToStream(bitMatrix, "PNG", pngOutputStream); + + return Base64.getEncoder().encodeToString(pngOutputStream.toByteArray()); + } + + /** + * OTP 체크. + * + * @param secretKey 비밀키 (32자리) + * @param otp OTP(6자리) + * @return true: 일치, false: 불일치 + */ + public static boolean checkOtp(String secretKey, String otp) + { + return otp.equals(getOtpCode(secretKey)); + } + + public static String getOtpCode(String secretKey) + { + Base32 base32 = new Base32(); + byte[] bytes = base32.decode(secretKey); + String hexKey = Hex.encodeHexString(bytes); + return TOTP.getOTP(hexKey); + } + + + +} \ No newline at end of file diff --git a/src/main/java/com/urpsys/basefront/common/service/LoginService.java b/src/main/java/com/urpsys/basefront/common/service/LoginService.java index bffec293..d4d2df3a 100644 --- a/src/main/java/com/urpsys/basefront/common/service/LoginService.java +++ b/src/main/java/com/urpsys/basefront/common/service/LoginService.java @@ -59,8 +59,9 @@ public class LoginService implements UserDetailsService log.info("srLoing 0 [{}]", srLoing[0]); log.info("srLoing 1 [{}]", srLoing[1]); + log.info("srLoing 2 [{}]", srLoing[2]); // sso 처리여부 추가 - if(srLoing.length != 2) + if(srLoing.length != 3) { return null; } @@ -71,11 +72,12 @@ public class LoginService implements UserDetailsService String strAuthClientSecret = "secretKey"; HttpResponse resAuth = Unirest.post(strAuthServerUrl) - .basicAuth(strAuthClientId , strAuthClientSecret) - .queryString("grant_type" , "password") - .queryString("username" , srLoing[0]) - .queryString("password" , srLoing[1]) - .asString(); + .basicAuth(strAuthClientId , strAuthClientSecret) + .queryString("grant_type" , "password") + .queryString("username" , srLoing[0]) + .queryString("password" , srLoing[1]) + .queryString("ssoYn" , srLoing[2]) + .asString(); String returnAuth = resAuth.getBody(); diff --git a/src/main/java/com/urpsys/basefront/common/util/CommonUtil.java b/src/main/java/com/urpsys/basefront/common/util/CommonUtil.java index 2d4b4431..48a8ea50 100644 --- a/src/main/java/com/urpsys/basefront/common/util/CommonUtil.java +++ b/src/main/java/com/urpsys/basefront/common/util/CommonUtil.java @@ -447,7 +447,7 @@ public class CommonUtil /** Map 데이터를 JSONObject로 변환. @version 1.0 - @author Yoon Su-wan + @author 나혁제 @since JDK1.0 @param v_msg Map @return JSONObject diff --git a/src/main/java/com/urpsys/basefront/config/SecurityConfig.java b/src/main/java/com/urpsys/basefront/config/SecurityConfig.java index 720931d7..6287def7 100644 --- a/src/main/java/com/urpsys/basefront/config/SecurityConfig.java +++ b/src/main/java/com/urpsys/basefront/config/SecurityConfig.java @@ -68,8 +68,10 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter .antMatchers("/egov/images/**" ).permitAll() .antMatchers("/EgovModal.do" ).permitAll() .antMatchers("/main/noAuth*.do" ).permitAll() - .antMatchers("//validator*" ).permitAll() + .antMatchers("/validator*" ).permitAll() + .antMatchers("/main/ssoDirectlogin.do" ).permitAll() // 2026.04.02 나혁제 SSO 로그인처리 + // .antMatchers("//validator*" ).permitAll() // .antMatchers("/main/searchIdFind.do" ).permitAll() // .antMatchers("/main/UserPasswordResetExt.do" ).permitAll() diff --git a/src/main/java/com/urpsys/basefront/config/WebConfig.java b/src/main/java/com/urpsys/basefront/config/WebConfig.java index d4d27838..d74fab87 100644 --- a/src/main/java/com/urpsys/basefront/config/WebConfig.java +++ b/src/main/java/com/urpsys/basefront/config/WebConfig.java @@ -7,6 +7,10 @@ import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import com.urpsys.basefront.interceptor.GoogleOtpCheckFrontInterceptor; +import com.urpsys.basefront.interceptor.ItsmMenuAuthCheckFrontInterceptor; +import com.urpsys.basefront.interceptor.UrpPortalFrontInterceptor; + /** * 기본 웹서버 설정 클리스 * @@ -37,6 +41,9 @@ public class WebConfig implements WebMvcConfigurer @Autowired ItsmMenuAuthCheckFrontInterceptor itsmMenuAuthCheckFrontInterceptor; + // 2026.04.03 나혁제 구글 OTP 2단계 처리 interceptor + @Autowired + GoogleOtpCheckFrontInterceptor googleOtpCheckFrontInterceptor; /* @Value("${custom.path.phy_sitemap}") @@ -52,6 +59,8 @@ public class WebConfig implements WebMvcConfigurer @Value("${custom.path.loc_svy}") private String resourcesUriPathSvy; // 파일 URL 주소 + @Value("${custom.GoogleOtpUseYn}") + private String strGoogleOtpUseYn; // 2026.04.03 나혁제 OTP 사용여부 @Override public void addResourceHandlers(ResourceHandlerRegistry registry) @@ -73,6 +82,18 @@ public class WebConfig implements WebMvcConfigurer public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(urpPortalFrontInterceptor).addPathPatterns("/**/*.do"); + + // 2026.04.03 나혁제 OTP 사용여부 + if(strGoogleOtpUseYn.equals("Y")) + { + registry.addInterceptor(googleOtpCheckFrontInterceptor).addPathPatterns("/main/*.do"); + registry.addInterceptor(googleOtpCheckFrontInterceptor).addPathPatterns("/srm/*.do"); + registry.addInterceptor(googleOtpCheckFrontInterceptor).addPathPatterns("/bbs/*.do"); + registry.addInterceptor(googleOtpCheckFrontInterceptor).addPathPatterns("/rem/*.do"); + registry.addInterceptor(googleOtpCheckFrontInterceptor).addPathPatterns("/sys/*.do"); + } + + // 2026.03.02 나혁제 url 보안영부 registry.addInterceptor(itsmMenuAuthCheckFrontInterceptor).addPathPatterns("/srm/*.do"); registry.addInterceptor(itsmMenuAuthCheckFrontInterceptor).addPathPatterns("/bbs/*.do"); registry.addInterceptor(itsmMenuAuthCheckFrontInterceptor).addPathPatterns("/rem/*.do"); diff --git a/src/main/java/com/urpsys/basefront/config/handler/CustomFailHandler.java b/src/main/java/com/urpsys/basefront/config/handler/CustomFailHandler.java index 43b63174..428c0db0 100644 --- a/src/main/java/com/urpsys/basefront/config/handler/CustomFailHandler.java +++ b/src/main/java/com/urpsys/basefront/config/handler/CustomFailHandler.java @@ -6,9 +6,11 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.springframework.context.annotation.Bean; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; +import org.springframework.stereotype.Component; import lombok.extern.slf4j.Slf4j; diff --git a/src/main/java/com/urpsys/basefront/config/handler/CustomSuccessHandler.java b/src/main/java/com/urpsys/basefront/config/handler/CustomSuccessHandler.java index b5446363..ede54808 100644 --- a/src/main/java/com/urpsys/basefront/config/handler/CustomSuccessHandler.java +++ b/src/main/java/com/urpsys/basefront/config/handler/CustomSuccessHandler.java @@ -11,6 +11,7 @@ import javax.servlet.http.HttpServletResponse; import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; +import org.springframework.stereotype.Component; import com.urpsys.basefront.common.exception.CustomException; import com.urpsys.basefront.common.util.CommonUtil; @@ -42,6 +43,7 @@ import lombok.extern.slf4j.Slf4j; @Slf4j +@Component public class CustomSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler { @Resource(name="RestApiCallUtil") diff --git a/src/main/java/com/urpsys/basefront/config/provider/CustomAuthenticationProvider.java b/src/main/java/com/urpsys/basefront/config/provider/CustomAuthenticationProvider.java index 1a914dc6..9e5037ba 100644 --- a/src/main/java/com/urpsys/basefront/config/provider/CustomAuthenticationProvider.java +++ b/src/main/java/com/urpsys/basefront/config/provider/CustomAuthenticationProvider.java @@ -54,7 +54,8 @@ public class CustomAuthenticationProvider implements AuthenticationProvider String username = (String) authentication.getPrincipal(); String password = (String) authentication.getCredentials(); - String strLoginInfo = username+","+password; + // 2026.04.02 나혁제 SSO 처리여부 추가 + String strLoginInfo = username+","+password+","+"N"; UserDetails info = loginService.loadUserByUsername(strLoginInfo); // 사용자 정보 추출 diff --git a/src/main/java/com/urpsys/basefront/controller/GoogleOtpController.java b/src/main/java/com/urpsys/basefront/controller/GoogleOtpController.java new file mode 100644 index 00000000..019cb9ac --- /dev/null +++ b/src/main/java/com/urpsys/basefront/controller/GoogleOtpController.java @@ -0,0 +1,175 @@ +package com.urpsys.basefront.controller; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.commons.codec.binary.Base32; +import org.egovframe.rte.fdl.property.EgovPropertyService; +import org.egovframe.rte.ptl.mvc.tags.ui.pagination.PaginationInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.ui.ModelMap; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.servlet.ModelAndView; + +import com.google.gson.FieldNamingPolicy; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.urpsys.basefront.common.egov.util.EgovStringUtil; +import com.urpsys.basefront.common.service.CommonService; +import com.urpsys.basefront.common.service.GoogleOtpService; +import com.urpsys.basefront.common.service.LoginService; +import com.urpsys.basefront.common.util.CommonUtil; +import com.urpsys.basefront.common.util.ConvertUtils; +import com.urpsys.basefront.common.util.RestApiCallUtil; +import com.urpsys.basefront.config.handler.CustomSuccessHandler; +import com.urpsys.basefront.domain.MemberVO; +import com.urpsys.basefront.domain.TokenInfo; +import com.urpsys.itmsfront.cmm.domain.ComDefaultCodeVO; +import com.urpsys.itmsfront.sys.domain.PrsnlPortletCreateVO; +import com.urpsys.itmsfront.sys.domain.PrsnlPortletManageVO; +import com.urpsys.itmsfront.sys.domain.UserDefaultVO; +import com.urpsys.itmsfront.sys.domain.UserManageVO; + +import kong.unirest.HttpResponse; +import kong.unirest.JsonNode; +import kong.unirest.Unirest; +import kong.unirest.json.JSONObject; +import lombok.extern.slf4j.Slf4j; + +/** + * SSO 처리 Controller + * @author urp 인프라본부 나혁제 + * @since 2026.04.02 + * @version 1.0 + * @see + * + *
+ * << 개정이력(Modification Information) >>
+ *
+ *  수정일           수정자       수정내용
+ *  ----------   --------   ---------------------------
+ *  2026.04.02     나혁제       최초 생성
+ *
+ * 
+ * + */ + +@Slf4j +@Controller +public class GoogleOtpController +{ + @Resource(name="RestApiCallUtil") + private RestApiCallUtil restApiCallUtil; + + /** + * otp key 발급처리 + * @author urp 인프라본부 나혁제 + * 작성일 : 2026.04.03 + */ + @RequestMapping(value = "/otp/OrRegist.do") + public String OrRegist ( HttpServletRequest request + , HttpServletResponse response + , Model model) throws Exception + { + log.info(">>>>>>>>>>>>>>> /otpOrRegist.do <<<<<<<<<<<<<<<"); + + Map bodyMap = new LinkedHashMap(); + Map returnMap = new LinkedHashMap(); + + String secretKey = GoogleOtpService.generateSecretKey(); + + log.info("secretKey [{}] ", secretKey); + + TokenInfo tokenInfo = CommonUtil.getTokenInfo(); + + // Body Setting Start --------------------------------- + bodyMap.put("uniqId", tokenInfo.getUniqId() ); + bodyMap.put("otpKey", secretKey ); + // Body Setting End --------------------------------- + + // RestApi Call Start --------------------------------- + returnMap = restApiCallUtil.RestApiCall(bodyMap, "/sys/updateOtpKey.do"); + // RestApi Call End --------------------------------- + + model.addAttribute("key", secretKey); + model.addAttribute("qr", GoogleOtpService.getQrCodeUrl("urITSM", secretKey)); + + log.info("<<<<<<<<<<<<<<< /otpOrRegist.do >>>>>>>>>>>>>>>"); + + return "/main/Login_otp_create"; + } + + /** + * otp 인증화면으로 이동처리 + * @author urp 인프라본부 나혁제 + * 작성일 : 2026.04.03 + */ + @RequestMapping(value = "/otp/checkView.do") + public String checkView ( HttpServletRequest request + , HttpServletResponse response + , Model model) throws Exception + { + log.info(">>>>>>>>>>>>>>> /otp/checkView.do <<<<<<<<<<<<<<<"); + + Map bodyMap = new LinkedHashMap(); + Map returnMap = new LinkedHashMap(); + + log.info("<<<<<<<<<<<<<<< /otp/checkView.do >>>>>>>>>>>>>>>"); + + return "/main/Login_otp_check"; + } + + @RequestMapping(value = "/otp/checkOtp.do") + public String check( HttpServletRequest request + , HttpServletResponse response + , Model model) + { + String strOtpSecretKey = CommonUtil.nvl(request.getSession().getAttribute("otpSecretKey")); // 인증키 + String strUserOtp = CommonUtil.nvl(request.getParameter("userOtp")); // otp + + boolean strOtpCheckYn = GoogleOtpService.checkOtp(strOtpSecretKey, strUserOtp); + + // 세션에 인증성공 처리 + if(strOtpCheckYn) + { + request.getSession().setAttribute("otpCheckYn", "Y"); + } + + return "forward:/main/mainPage.do"; + } + + + + + + + + + +} diff --git a/src/main/java/com/urpsys/basefront/controller/MainController.java b/src/main/java/com/urpsys/basefront/controller/MainController.java index d8cf689b..892624ff 100644 --- a/src/main/java/com/urpsys/basefront/controller/MainController.java +++ b/src/main/java/com/urpsys/basefront/controller/MainController.java @@ -15,7 +15,12 @@ import org.egovframe.rte.fdl.property.EgovPropertyService; import org.egovframe.rte.ptl.mvc.tags.ui.pagination.PaginationInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.ui.ModelMap; @@ -31,9 +36,11 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.urpsys.basefront.common.egov.util.EgovStringUtil; import com.urpsys.basefront.common.service.CommonService; +import com.urpsys.basefront.common.service.LoginService; import com.urpsys.basefront.common.util.CommonUtil; import com.urpsys.basefront.common.util.ConvertUtils; import com.urpsys.basefront.common.util.RestApiCallUtil; +import com.urpsys.basefront.config.handler.CustomSuccessHandler; import com.urpsys.basefront.domain.MemberVO; import com.urpsys.basefront.domain.TokenInfo; import com.urpsys.itmsfront.cmm.domain.ComDefaultCodeVO; @@ -86,6 +93,12 @@ public class MainController @Autowired private CommonService commonService; + @Autowired + private LoginService loginService; + + @Autowired + private CustomSuccessHandler customSuccessHandler; + // @Autowired // HtmlEmailUtil htmlEmailUtil; @@ -150,6 +163,10 @@ public class MainController { strErrorMsg = "사용자 정보는 존재하나 권한정보가 존재하지 않습니다. 시스템 관리자에게 연락해 주세요."; } + else if(srError[0].equals("-5")) + { + strErrorMsg = "SSO 인증처리 실패하였습니다. 시스템 관리자에게 연락해 주세요."; + } else { strErrorMsg = ""; @@ -174,6 +191,8 @@ public class MainController { // 메인 페이지 이동 strReturnJsp = "forward:/main/mainPage.do"; + // strReturnJsp = "forward:/otpOrRegist.do"; + } log.info("<<<<<<<<<<<<<<< /main/actionMain.do >>>>>>>>>>>>>>>"); @@ -203,11 +222,11 @@ public class MainController String strAuthUrl = strAuthServer+"/oauth/token"; HttpResponse resAuth = Unirest.post(strAuthUrl) - .basicAuth("clientId", "secretKey") - .queryString("grant_type", "password") - .queryString("username", strId) - .queryString("password", strPassWord) - .asString(); + .basicAuth("clientId", "secretKey") + .queryString("grant_type", "password") + .queryString("username", strId) + .queryString("password", strPassWord) + .asString(); String returnAuth = resAuth.getBody(); @@ -684,11 +703,6 @@ public class MainController - - - - - diff --git a/src/main/java/com/urpsys/basefront/controller/SsoController.java b/src/main/java/com/urpsys/basefront/controller/SsoController.java new file mode 100644 index 00000000..fc88194f --- /dev/null +++ b/src/main/java/com/urpsys/basefront/controller/SsoController.java @@ -0,0 +1,169 @@ +package com.urpsys.basefront.controller; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.egovframe.rte.fdl.property.EgovPropertyService; +import org.egovframe.rte.ptl.mvc.tags.ui.pagination.PaginationInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.ui.ModelMap; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.servlet.ModelAndView; + +import com.google.gson.FieldNamingPolicy; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.urpsys.basefront.common.egov.util.EgovStringUtil; +import com.urpsys.basefront.common.service.CommonService; +import com.urpsys.basefront.common.service.LoginService; +import com.urpsys.basefront.common.util.CommonUtil; +import com.urpsys.basefront.common.util.ConvertUtils; +import com.urpsys.basefront.common.util.RestApiCallUtil; +import com.urpsys.basefront.config.handler.CustomSuccessHandler; +import com.urpsys.basefront.domain.MemberVO; +import com.urpsys.basefront.domain.TokenInfo; +import com.urpsys.itmsfront.cmm.domain.ComDefaultCodeVO; +import com.urpsys.itmsfront.sys.domain.PrsnlPortletCreateVO; +import com.urpsys.itmsfront.sys.domain.PrsnlPortletManageVO; +import com.urpsys.itmsfront.sys.domain.UserDefaultVO; +import com.urpsys.itmsfront.sys.domain.UserManageVO; + +import kong.unirest.HttpResponse; +import kong.unirest.JsonNode; +import kong.unirest.Unirest; +import kong.unirest.json.JSONObject; +import lombok.extern.slf4j.Slf4j; + +/** + * SSO 처리 Controller + * @author urp 인프라본부 나혁제 + * @since 2026.04.02 + * @version 1.0 + * @see + * + *
+ * << 개정이력(Modification Information) >>
+ *
+ *  수정일           수정자       수정내용
+ *  ----------   --------   ---------------------------
+ *  2026.04.02     나혁제       최초 생성
+ *
+ * 
+ * + */ + +@Slf4j +@Controller +public class SsoController +{ + @Autowired + private LoginService loginService; + + @Autowired + private CustomSuccessHandler customSuccessHandler; + + /** + * SSO 연동 로그인 처리 + * @author urp 인프라본부 나혁제 + * 작성일 : 2026.04.02 + */ + @RequestMapping(value = "/main/ssoDirectlogin.do") + public String ssoDirectlogin( HttpServletRequest request + , HttpServletResponse response + , ModelMap model) throws Exception + { + log.info(">>>>>>>>>>>>>>> /main/ssoDirectlogin.do <<<<<<<<<<<<<<<"); + + // --- SSO 연동 Start --------------------------------- + // boolean bSsoAuthYn = false; + boolean bSsoAuthYn = true; + + // sso 인증처리 + + + + + + if(!bSsoAuthYn) + { + return "forward:/main/actionMain.do?error=-5:ssoFail"; + } + // --- SSO 연동 End --------------------------------- + + + + + // 인증 Start ---- + // String username = (String)request.getParameter("userId"); + // String password = ""; + + String username = (String)request.getParameter("userId"); + String password = "sso"; + + log.info("username => {}" , username ); + log.info("password => {}" , password ); + + String strLoginInfo = username+","+password+","+"Y"; + + UserDetails info = loginService.loadUserByUsername(strLoginInfo); // 사용자 정보 추출 + + MemberVO member = (MemberVO) info; + + if(info == null) + { + return "forward:/main/actionMain.do?error=-5:ssoFail"; + } + + // 시스템 토큰 등록 + UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(info, null, info.getAuthorities()); + + // 시스템 보안 등록 + SecurityContext context = SecurityContextHolder.createEmptyContext(); + context.setAuthentication(auth); + SecurityContextHolder.setContext(context); + + // + request.getSession(true).setAttribute("SPRING_SECURITY_CONTEXT", context); + + // 로그인 성공처리 + customSuccessHandler.onAuthenticationSuccess(request, response, auth); + + log.info("<<<<<<<<<<<<<<< /main/ssoDirectlogin.do >>>>>>>>>>>>>>>"); + + return null; + + } + + + + + + + + + + + + +} diff --git a/src/main/java/com/urpsys/basefront/interceptor/GoogleOtpCheckFrontInterceptor.java b/src/main/java/com/urpsys/basefront/interceptor/GoogleOtpCheckFrontInterceptor.java new file mode 100644 index 00000000..9815fb88 --- /dev/null +++ b/src/main/java/com/urpsys/basefront/interceptor/GoogleOtpCheckFrontInterceptor.java @@ -0,0 +1,131 @@ +package com.urpsys.basefront.interceptor; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.ModelAndView; + +import com.urpsys.basefront.common.util.CommonUtil; +import com.urpsys.basefront.common.util.RestApiCallUtil; +import com.urpsys.basefront.domain.TokenInfo; + +import lombok.extern.slf4j.Slf4j; + +/** + * Controller Google OTP Check interceptor 클리스 + * + * @author urp 인프라본부 나혁제 + * @since 2026.04.03 + * @version 1.0.0 + * @see + * + *
+ *
+ * << 개정이력(Modification information) >>
+ *
+ *   수정일        수정자         수정내용
+ * -----------  ---------    ------------------------
+ * 2026.04.03    나혁제         최초작성
+ *
+ * 
+ */ + +@Slf4j +@Component +public class GoogleOtpCheckFrontInterceptor implements HandlerInterceptor +{ + @Resource(name="RestApiCallUtil") + private RestApiCallUtil restApiCallUtil; + + // 컨트롤러가 호출되기 전 + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception + { + log.info(" >>>>>>>>>> preHandle <<<<<<<<<< "); + + Map bodyMap = new LinkedHashMap(); + Map returnMap = new LinkedHashMap(); + + // 로그아웃인경우 return; + if(request.getSession().getAttribute("tokenInfo") == null) + { + return true; + } + + // 인증키 체크 + String strOtpSecretKey = CommonUtil.nvl(request.getSession().getAttribute("otpSecretKey")); + + // 키가 없는경우 개인키 추출 + if(strOtpSecretKey.equals("")) + { + TokenInfo tokenInfo = CommonUtil.getTokenInfo(); + + // Body Setting Start --------------------------------- + bodyMap.put("uniqId" , tokenInfo.getUniqId()); + // Body Setting End --------------------------------- + + // RestApi Call Start --------------------------------- + returnMap = restApiCallUtil.RestApiCall(bodyMap, "/sys/selectOtpKey.do"); + // RestApi Call End --------------------------------- + + strOtpSecretKey = CommonUtil.nvl(returnMap.get("strOtpKey")); + + // 키 발급이 안된경우 키 발급처리 + if(strOtpSecretKey.equals("")) + { + response.sendRedirect("/otp/OrRegist.do"); + return true; + } + + // 세션 키 등록 처리 + request.getSession().setAttribute("otpSecretKey", strOtpSecretKey); + } + + // otp 인증여부 확인 + String strOtpCheckYn = CommonUtil.nvl(request.getSession().getAttribute("otpCheckYn")); + + if(!strOtpCheckYn.equals("Y")) + { + // otp 인증 페이지로 이동처리 + response.sendRedirect("/otp/checkView.do"); + return true; + } + + + log.info(" <<<<<<<<<< preHandle >>>>>>>>>> "); + + return true; + } + + // controller의 handler가 끝나면 처리됨 + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, + ModelAndView modelAndView) throws Exception + { + /* + log.info(" >>>>>>>>>> postHandle <<<<<<<<<< "); + log.info(" <<<<<<<<<< postHandle >>>>>>>>>> "); + */ + + } + + // 컨트롤러가 처리 완료후 + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) + throws Exception + { + /* + log.info(" >>>>>>>>>> afterCompletion <<<<<<<<<< "); + log.info(" <<<<<<<<<< afterCompletion >>>>>>>>>> "); + */ + + } + +} diff --git a/src/main/java/com/urpsys/basefront/config/ItsmMenuAuthCheckFrontInterceptor.java b/src/main/java/com/urpsys/basefront/interceptor/ItsmMenuAuthCheckFrontInterceptor.java similarity index 98% rename from src/main/java/com/urpsys/basefront/config/ItsmMenuAuthCheckFrontInterceptor.java rename to src/main/java/com/urpsys/basefront/interceptor/ItsmMenuAuthCheckFrontInterceptor.java index f07111f4..cea3b6f0 100644 --- a/src/main/java/com/urpsys/basefront/config/ItsmMenuAuthCheckFrontInterceptor.java +++ b/src/main/java/com/urpsys/basefront/interceptor/ItsmMenuAuthCheckFrontInterceptor.java @@ -1,4 +1,4 @@ -package com.urpsys.basefront.config; +package com.urpsys.basefront.interceptor; import java.util.List; import java.util.Map; diff --git a/src/main/java/com/urpsys/basefront/config/UrpPortalFrontInterceptor.java b/src/main/java/com/urpsys/basefront/interceptor/UrpPortalFrontInterceptor.java similarity index 94% rename from src/main/java/com/urpsys/basefront/config/UrpPortalFrontInterceptor.java rename to src/main/java/com/urpsys/basefront/interceptor/UrpPortalFrontInterceptor.java index d38623e4..248fb4fe 100644 --- a/src/main/java/com/urpsys/basefront/config/UrpPortalFrontInterceptor.java +++ b/src/main/java/com/urpsys/basefront/interceptor/UrpPortalFrontInterceptor.java @@ -1,4 +1,4 @@ -package com.urpsys.basefront.config; +package com.urpsys.basefront.interceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; diff --git a/src/main/java/com/urpsys/itmsfront/pot/controller/PortletManageController.java b/src/main/java/com/urpsys/itmsfront/pot/controller/PortletManageController.java index 7a974ed4..3794eeb6 100644 --- a/src/main/java/com/urpsys/itmsfront/pot/controller/PortletManageController.java +++ b/src/main/java/com/urpsys/itmsfront/pot/controller/PortletManageController.java @@ -53,7 +53,8 @@ import lombok.extern.slf4j.Slf4j; */ @Slf4j @Controller -public class PortletManageController { +public class PortletManageController +{ @Resource(name="RestApiCallUtil") private RestApiCallUtil restApiCallUtil; diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index 647ab450..4faf831e 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -53,5 +53,7 @@ client : kintex # 2026.03.12 URL 권한 체크 여부 urlAuthCheck : Y + # 2026.04.02 GoogleOTP 사용여부 체크 + GoogleOtpUseYn : N \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/jsp/main/Login_otp_check.jsp b/src/main/webapp/WEB-INF/jsp/main/Login_otp_check.jsp new file mode 100644 index 00000000..8bca428d --- /dev/null +++ b/src/main/webapp/WEB-INF/jsp/main/Login_otp_check.jsp @@ -0,0 +1,109 @@ + + +<%-- + Class Name : LoginUsr.jsp + Description : 로그인화면 + Modification Information + + 수정일 수정자 수정내용 + ------- -------- --------------------------- + 2025.01.03 나혁제 최초생성 + + author : 인프라본부 나혁제 + since : 2025.01.02 +--%> +<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> + +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> + + + + UR-ITSM + + + + + + + urITSM + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+

uWorks Portal logo

+

urITSM 에 오신것을 환영합니다.

+ + + +
+ + +
+ + + diff --git a/src/main/webapp/WEB-INF/jsp/main/Login_otp_create.jsp b/src/main/webapp/WEB-INF/jsp/main/Login_otp_create.jsp new file mode 100644 index 00000000..d955cf13 --- /dev/null +++ b/src/main/webapp/WEB-INF/jsp/main/Login_otp_create.jsp @@ -0,0 +1,106 @@ + + +<%-- + Class Name : LoginUsr.jsp + Description : 로그인화면 + Modification Information + + 수정일 수정자 수정내용 + ------- -------- --------------------------- + 2025.01.03 나혁제 최초생성 + + author : 인프라본부 나혁제 + since : 2025.01.02 +--%> +<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> + +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> + + + + UR-ITSM + + + + + + + urITSM + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+

uWorks Portal logo

+

urITSM 에 오신것을 환영합니다.

+ + + +
+ + +
+ + +