This commit is contained in:
@@ -7,6 +7,19 @@
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
|
||||
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
|
||||
<%@ include file="/jsp/common/include/localemessage.jsp" %>
|
||||
<%
|
||||
// 비밀번호 규칙 안내문구용 모니터링 프로퍼티 조회
|
||||
com.eactive.eai.rms.common.context.MonitoringContext monitoringContext =
|
||||
(com.eactive.eai.rms.common.context.MonitoringContext) WebApplicationContextUtils
|
||||
.getRequiredWebApplicationContext(pageContext.getServletContext())
|
||||
.getBean("monitoringContext");
|
||||
int pwdLengthCheck = monitoringContext.getIntProperty(
|
||||
com.eactive.eai.rms.common.context.MonitoringContext.RMS_PASSWORD_LENGTH_CHECK, 7);
|
||||
int pwdCombiCheck = monitoringContext.getIntProperty(
|
||||
com.eactive.eai.rms.common.context.MonitoringContext.RMS_PASSWORD_COMBI_CHECK, 2);
|
||||
int pwdRepeatCheck = monitoringContext.getIntProperty(
|
||||
com.eactive.eai.rms.common.context.MonitoringContext.RMS_PASSWORD_REPEAT_CHECK, 3);
|
||||
%>
|
||||
<c:set var="themeColor" value="<%=System.getProperty(\"theme.color\")%>" scope="session" />
|
||||
|
||||
<%
|
||||
@@ -481,8 +494,8 @@
|
||||
<input type="password" name="confirmPassword" class="form-control rounded-left" placeholder="<%= localeMessage.getString("login.placeholderConfirmationPassword") %>" autocomplete="off" required>
|
||||
</div>
|
||||
<span style="font-size:0.8em; color:red">
|
||||
※ 7글자 이상 & 영문/숫자/특수문자 2종류 이상<br/>
|
||||
※ 연속된 숫자/문자(예: 123, abc, qwer), 동일 문자 3자 이상 반복 사용 불가
|
||||
※ <%= pwdLengthCheck %>글자 이상 & 영문/숫자/특수문자 <%= pwdCombiCheck %>종류 이상<br/>
|
||||
※ 연속된 숫자/문자(예: 123, abc, qwer) 사용 불가<%= pwdRepeatCheck >= 2 ? ", 동일 문자 " + pwdRepeatCheck + "자 이상 반복 불가" : "" %>
|
||||
</span>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
||||
@@ -179,8 +179,8 @@
|
||||
autowidth: true,
|
||||
viewrecords : true,
|
||||
gridview : true,
|
||||
ondblClickRow : function(rowId) {
|
||||
console.log("rowId", rowId);
|
||||
ondblClickRow : function(rowId) {
|
||||
/* console.log("rowId", rowId);
|
||||
var rowData = $(this)
|
||||
.getRowData(rowId);
|
||||
var key = rowData['EaiSevrInstncName'];
|
||||
@@ -193,7 +193,7 @@
|
||||
url2 += "&searchAdptrBzwkGroupName="
|
||||
+ key2;
|
||||
url2 += '&menuId='+'${param.menuId}';
|
||||
goNav(url2);
|
||||
goNav(url2); */
|
||||
},
|
||||
loadComplete : function(d) {
|
||||
$("button[name*=img]").unbind("click");
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
<div class="search_wrap">
|
||||
<button type="button" class="cssbtn" id="btn_previous" level="R" status="DETAIL,NEW"><i class="material-icons">arrow_back</i> <%= localeMessage.getString("button.previous") %></button>
|
||||
</div>
|
||||
<div class="title" id="title">전문레이아웃 연동 이력 상세</div>
|
||||
<div class="title" id="title">연동 배포 이력 상세</div>
|
||||
<table class="table_row" cellspacing="0">
|
||||
<colgroup>
|
||||
<col style="width:12%"/><col style="width:38%"/>
|
||||
|
||||
@@ -530,6 +530,10 @@
|
||||
if (confirm("<%= localeMessage.getString("common.checkSave")%>") != true) return;
|
||||
|
||||
var formData = new FormData($("#ajaxForm")[0]);
|
||||
// Summernote 그림 다이얼로그의 내부 파일 input(name="files")이 #ajaxForm 안에 있어
|
||||
// 선택한 이미지가 지워지지 않고 남아 있으면 여기서 함께 딸려 온다.
|
||||
// 본 화면은 첨부파일 기능을 쓰지 않으므로 항상 제거한다.
|
||||
formData.delete("files");
|
||||
formData.set("useYn", $("#useYn").is(":checked") ? "Y" : "N");
|
||||
formData.set("fixYn", $("#fixYn").is(":checked") ? "Y" : "N");
|
||||
formData.set("noticeDetail", $('#contents').summernote('code'));
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
|
||||
// 총건수 도넛 차트
|
||||
var totalDonutOption = {
|
||||
color: ['#5470C6', '#FAC858', '#EE6666'],
|
||||
title: {
|
||||
text: '총 건수 분포',
|
||||
left: 'center',
|
||||
@@ -111,7 +112,7 @@
|
||||
show: true
|
||||
},
|
||||
data: [
|
||||
{ value: 0, name: '성공', itemStyle: { color: '#91CC75' } },
|
||||
{ value: 0, name: '성공', itemStyle: { color: '#5470C6' } },
|
||||
{ value: 0, name: 'Timeout', itemStyle: { color: '#FAC858' } },
|
||||
{ value: 0, name: '시스템오류', itemStyle: { color: '#EE6666' } }
|
||||
]
|
||||
|
||||
@@ -71,6 +71,7 @@
|
||||
|
||||
// 총건수 도넛 차트
|
||||
var totalDonutOption = {
|
||||
color: ['#5470C6', '#FAC858', '#EE6666'],
|
||||
title: {
|
||||
text: '총 건수 분포',
|
||||
left: 'center',
|
||||
@@ -112,7 +113,7 @@
|
||||
show: true
|
||||
},
|
||||
data: [
|
||||
{ value: 0, name: '성공', itemStyle: { color: '#91CC75' } },
|
||||
{ value: 0, name: '성공', itemStyle: { color: '#5470C6' } },
|
||||
{ value: 0, name: 'Timeout', itemStyle: { color: '#FAC858' } },
|
||||
{ value: 0, name: '시스템오류', itemStyle: { color: '#EE6666' } }
|
||||
]
|
||||
|
||||
@@ -63,6 +63,9 @@
|
||||
|
||||
// 총건수 도넛 차트
|
||||
var totalDonutOption = {
|
||||
// updateCharts()에서 series[].data를 itemStyle 없이 재설정하면 조각별 itemStyle.color가
|
||||
// 병합 과정에서 유실되므로, 옵션 레벨 color 팔레트(성공/Timeout/시스템오류 순)로 색을 고정한다.
|
||||
color: ['#5470C6', '#FAC858', '#EE6666'],
|
||||
title: {
|
||||
text: '총 건수 분포',
|
||||
left: 'center',
|
||||
@@ -104,7 +107,7 @@
|
||||
show: true
|
||||
},
|
||||
data: [
|
||||
{ value: 0, name: '성공', itemStyle: { color: '#91CC75' } },
|
||||
{ value: 0, name: '성공', itemStyle: { color: '#5470C6' } },
|
||||
{ value: 0, name: 'Timeout', itemStyle: { color: '#FAC858' } },
|
||||
{ value: 0, name: '시스템오류', itemStyle: { color: '#EE6666' } }
|
||||
]
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
|
||||
// 총건수 도넛 차트
|
||||
var totalDonutOption = {
|
||||
color: ['#5470C6', '#FAC858', '#EE6666'],
|
||||
title: {
|
||||
text: '총 건수 분포',
|
||||
left: 'center',
|
||||
@@ -99,7 +100,7 @@
|
||||
show: true
|
||||
},
|
||||
data: [
|
||||
{ value: 0, name: '성공', itemStyle: { color: '#91CC75' } },
|
||||
{ value: 0, name: '성공', itemStyle: { color: '#5470C6' } },
|
||||
{ value: 0, name: 'Timeout', itemStyle: { color: '#FAC858' } },
|
||||
{ value: 0, name: '시스템오류', itemStyle: { color: '#EE6666' } }
|
||||
]
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
|
||||
// 총건수 도넛 차트
|
||||
var totalDonutOption = {
|
||||
color: ['#5470C6', '#FAC858', '#EE6666'],
|
||||
title: {
|
||||
text: '총 건수 분포',
|
||||
left: 'center',
|
||||
@@ -99,7 +100,7 @@
|
||||
show: true
|
||||
},
|
||||
data: [
|
||||
{ value: 0, name: '성공', itemStyle: { color: '#91CC75' } },
|
||||
{ value: 0, name: '성공', itemStyle: { color: '#5470C6' } },
|
||||
{ value: 0, name: 'Timeout', itemStyle: { color: '#FAC858' } },
|
||||
{ value: 0, name: '시스템오류', itemStyle: { color: '#EE6666' } }
|
||||
]
|
||||
|
||||
@@ -276,6 +276,15 @@ public interface MonitoringContext {
|
||||
// 비밀번호 변경 시 SMS 2차 인증 사용 여부 (djb.sms_auth.enabled 와 함께 true 여야 동작)
|
||||
public static final String RMS_PASSWORD_SMS_AUTH_ENABLED = "rms.password.sms_auth.enabled";
|
||||
|
||||
// 비밀번호 최소 길이 (기본 7)
|
||||
public static final String RMS_PASSWORD_LENGTH_CHECK = "rms.password.length.check";
|
||||
|
||||
// 비밀번호 문자 조합 종류 수 (영문/숫자/특수문자 중 N종류 이상, 기본 2)
|
||||
public static final String RMS_PASSWORD_COMBI_CHECK = "rms.password.combi.check";
|
||||
|
||||
// 동일 문자 연속 반복 제한 개수 (기본 3, 2 미만이면 미검사)
|
||||
public static final String RMS_PASSWORD_REPEAT_CHECK = "rms.password.repeat.check";
|
||||
|
||||
// API 상태변화 스윙챗 발송여부
|
||||
public static final String DJB_UMS_MESSENGER_APIMONITOR_ENABLED = "djb.ums.messenger.api-monitor.enabled";
|
||||
|
||||
|
||||
@@ -67,6 +67,9 @@ public class MainController implements InterceptorSkipController {
|
||||
private static final String USER_STATUS_LOCKED = "2";
|
||||
private static final int DEFAULT_MAX_LOGIN_FAIL_COUNT = 5;
|
||||
private static final int DEFAULT_PASSWORD_HISTORY_COUNT = 5;
|
||||
private static final int DEFAULT_PASSWORD_LENGTH_CHECK = 7;
|
||||
private static final int DEFAULT_PASSWORD_COMBI_CHECK = 2;
|
||||
private static final int DEFAULT_PASSWORD_REPEAT_CHECK = 3;
|
||||
|
||||
private final LocaleMessage localeMessage;
|
||||
private final MonitoringContext monitoringContext;
|
||||
@@ -469,6 +472,24 @@ public class MainController implements InterceptorSkipController {
|
||||
return monitoringContext.getBooleanProperty(MonitoringContext.RMS_PASSWORD_SMS_AUTH_ENABLED, false);
|
||||
}
|
||||
|
||||
// 비밀번호 최소 길이 조회 (rms.password.length.check)
|
||||
private int getPasswordLengthCheck() {
|
||||
return monitoringContext.getIntProperty(
|
||||
MonitoringContext.RMS_PASSWORD_LENGTH_CHECK, DEFAULT_PASSWORD_LENGTH_CHECK);
|
||||
}
|
||||
|
||||
// 비밀번호 문자 조합 종류 수 조회 (rms.password.combi.check, 영문/숫자/특수문자 중 N종류 이상)
|
||||
private int getPasswordCombiCheck() {
|
||||
return monitoringContext.getIntProperty(
|
||||
MonitoringContext.RMS_PASSWORD_COMBI_CHECK, DEFAULT_PASSWORD_COMBI_CHECK);
|
||||
}
|
||||
|
||||
// 동일 문자 연속 반복 제한 개수 조회 (rms.password.repeat.check, 2 미만이면 미검사)
|
||||
private int getPasswordRepeatCheck() {
|
||||
return monitoringContext.getIntProperty(
|
||||
MonitoringContext.RMS_PASSWORD_REPEAT_CHECK, DEFAULT_PASSWORD_REPEAT_CHECK);
|
||||
}
|
||||
|
||||
// 로그인 실패 횟수 증가, 임계치 도달 시 계정 잠금
|
||||
private int increaseLoginFailCount(UserInfo userInfo) {
|
||||
int failCount = (userInfo.getLoginfailcount() == null ? 0 : userInfo.getLoginfailcount()) + 1;
|
||||
@@ -1018,10 +1039,17 @@ public class MainController implements InterceptorSkipController {
|
||||
|
||||
private boolean isPasswordValid(String password) {
|
||||
|
||||
return password != null && password.getBytes().length == password
|
||||
.length() && password.getBytes().length >= 7
|
||||
&& isCombination(password)
|
||||
&& !isRepeatPassword(password, PASSWORD_PATTERN_CHECK_LENGTH)
|
||||
if (password == null || password.getBytes().length != password.length()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int lengthCheck = getPasswordLengthCheck();
|
||||
int combiCheck = getPasswordCombiCheck();
|
||||
int repeatCheck = getPasswordRepeatCheck();
|
||||
|
||||
return password.getBytes().length >= lengthCheck
|
||||
&& isCombination(password, combiCheck)
|
||||
&& (repeatCheck < 2 || !isRepeatPassword(password, repeatCheck))
|
||||
&& !isSerialPassword(password, PASSWORD_PATTERN_CHECK_LENGTH)
|
||||
&& !isKeyboardSequentialPassword(password, PASSWORD_PATTERN_CHECK_LENGTH);
|
||||
}
|
||||
@@ -1088,7 +1116,7 @@ public class MainController implements InterceptorSkipController {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isCombination(String password) {
|
||||
private boolean isCombination(String password, int minTypes) {
|
||||
int combicount = 0;
|
||||
// 숫자포함여부
|
||||
String pattern = "[0-9]+";
|
||||
@@ -1117,8 +1145,8 @@ public class MainController implements InterceptorSkipController {
|
||||
combicount++;
|
||||
}
|
||||
|
||||
// combicount가 2 이상이면 true, 그렇지 않으면 false 반환
|
||||
return combicount >= 2;
|
||||
// combicount가 minTypes 이상이면 true, 그렇지 않으면 false 반환
|
||||
return combicount >= minTypes;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +60,9 @@ public class PortalNoticeManService extends BaseService {
|
||||
private static final String MANUAL_TITLE_KEYWORD = "장애";
|
||||
|
||||
private String decodeString(String value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (ContainerUtil.get() == ContainerUtil.TOMCAT) {
|
||||
try {
|
||||
return new String(value.getBytes("euc-kr"), StandardCharsets.UTF_8);
|
||||
@@ -433,7 +436,8 @@ public class PortalNoticeManService extends BaseService {
|
||||
MultipartFile file = portalNoticeUI.getFiles();
|
||||
|
||||
if (file != null && !file.isEmpty()) { // 새로운 파일이 업로드된 경우에만 처리
|
||||
String decodedFileName = decodeString(portalNoticeUI.getFileName());
|
||||
String fileName = StringUtils.defaultIfBlank(portalNoticeUI.getFileName(), file.getOriginalFilename());
|
||||
String decodedFileName = decodeString(fileName);
|
||||
FileTypeContext.setFileType("notice");
|
||||
FileInfo fileInfo = fileService.createOrUpdateSingleFile(portalNotice.getFileId(), file, decodedFileName, true);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user