mirror of
https://gitee.com/dromara/MaxKey.git
synced 2025-12-08 01:48:33 +08:00
Merge branch 'master' of https://github.com/MaxKeyTop/MaxKey
This commit is contained in:
commit
ba681ed7ca
10
README.md
10
README.md
@ -92,17 +92,15 @@ App Management UI
|
|||||||
Download the current version of Baidu Pan,<a href="https://maxkey.top/zh/about/download.html" target="_blank"> history version</a>
|
Download the current version of Baidu Pan,<a href="https://maxkey.top/zh/about/download.html" target="_blank"> history version</a>
|
||||||
| Version | ReleaseDate | Download URL | Code |
|
| Version | ReleaseDate | Download URL | Code |
|
||||||
| --------| :----- | :---- | :----: |
|
| --------| :----- | :---- | :----: |
|
||||||
| v 2.3.0 GA | 2020/11/11 | <a href="https://pan.baidu.com/s/17jAatKNlM6L649992kEMBQ" target="_blank">Download</a> | **h3zw** |
|
| v 2.4.0 RC | 2020/12/15 | <a href="https://pan.baidu.com/s/1xUZZJrxEUmbU3thIxd2lDA" target="_blank">Download</a> | **k65z** |
|
||||||
|
|
||||||
|
|
||||||
# Roadmap
|
# Roadmap
|
||||||
|
|
||||||
1. Implementation of dynamic group (based on user attribute or organization)
|
1. Part-time organizations
|
||||||
|
|
||||||
2. Director and part-time organizations
|
2. Zero trust scenario integration
|
||||||
|
|
||||||
3. Zero trust scenario integration
|
3. Maxkey-Cloud (micro service version)-2021
|
||||||
|
|
||||||
4. Maxkey-Cloud (micro service version)-2021
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
10
README_en.md
10
README_en.md
@ -92,17 +92,15 @@ App Management UI
|
|||||||
Download the current version of Baidu Pan,<a href="https://maxkey.top/zh/about/download.html" target="_blank"> history version</a>
|
Download the current version of Baidu Pan,<a href="https://maxkey.top/zh/about/download.html" target="_blank"> history version</a>
|
||||||
| Version | Date | URL | Code |
|
| Version | Date | URL | Code |
|
||||||
| --------| :----- | :---- | :----: |
|
| --------| :----- | :---- | :----: |
|
||||||
| v 2.3.0 GA | 2020/11/11 | <a href="https://pan.baidu.com/s/17jAatKNlM6L649992kEMBQ" target="_blank">Download</a> | **h3zw** |
|
| v 2.4.0 RC | 2020/12/15 | <a href="https://pan.baidu.com/s/1xUZZJrxEUmbU3thIxd2lDA" target="_blank">Download</a> | **k65z** |
|
||||||
|
|
||||||
|
|
||||||
# Roadmap
|
# Roadmap
|
||||||
|
|
||||||
1. Implementation of dynamic group (based on user attribute or organization)
|
1. Part-time organizations
|
||||||
|
|
||||||
2. Director and part-time organizations
|
2. Zero trust scenario integration
|
||||||
|
|
||||||
3. Zero trust scenario integration
|
3. Maxkey-Cloud (micro service version)-2021
|
||||||
|
|
||||||
4. Maxkey-Cloud (micro service version)-2021
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
10
README_zh.md
10
README_zh.md
@ -93,17 +93,15 @@ QQ交流群:<b>434469201</b>
|
|||||||
当前版本百度网盘下载,<a href="https://maxkey.top/zh/about/download.html" target="_blank"> 历史版本</a>
|
当前版本百度网盘下载,<a href="https://maxkey.top/zh/about/download.html" target="_blank"> 历史版本</a>
|
||||||
| 版本 | 日期 | 下载地址 | 提取码 |
|
| 版本 | 日期 | 下载地址 | 提取码 |
|
||||||
| --------| :----- | :---- | :----: |
|
| --------| :----- | :---- | :----: |
|
||||||
| v 2.3.0 GA | 2020/11/11 | <a href="https://pan.baidu.com/s/17jAatKNlM6L649992kEMBQ" target="_blank">链接下载</a> | **h3zw** |
|
| v 2.4.0 RC | 2020/12/15 | <a href="https://pan.baidu.com/s/1xUZZJrxEUmbU3thIxd2lDA" target="_blank">链接下载</a> | **k65z** |
|
||||||
|
|
||||||
|
|
||||||
# Roadmap
|
# Roadmap
|
||||||
|
|
||||||
1.动态用户组实现(基于用户属性或机构)
|
1.兼职机构
|
||||||
|
|
||||||
2.主任职机构和兼职机构
|
2.零信任场景整合
|
||||||
|
|
||||||
3.零信任场景整合
|
3.MaxKey Cloud(微服务版)-2021年
|
||||||
|
|
||||||
4.MaxKey Cloud(微服务版)-2021年
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
MaxKey v 2.4.0 GA 2020/12/**
|
MaxKey v 2.4.0 RC 2020/12/16
|
||||||
*(MAXKEY-201001) 动态用户组实现(基于用户属性或机构)
|
*(MAXKEY-201001) 动态用户组实现(基于用户属性或机构)
|
||||||
*(MAXKEY-201002) 任职机构和兼职机构
|
*(MAXKEY-201002) 任职机构和兼职机构
|
||||||
*(MAXKEY-201003) 登录会话切换的优化
|
*(MAXKEY-201003) 登录会话切换的优化
|
||||||
@ -14,10 +14,14 @@
|
|||||||
*(MAXKEY-201013) SAML 2.0 Metadata优化
|
*(MAXKEY-201013) SAML 2.0 Metadata优化
|
||||||
*(MAXKEY-201014) HandlerInterceptorAdapter@deprecated 调整为 AsyncHandlerInterceptor
|
*(MAXKEY-201014) HandlerInterceptorAdapter@deprecated 调整为 AsyncHandlerInterceptor
|
||||||
*(MAXKEY-201015) mybatis-jpa升级,添加@Entity和@Transient支持,优化update时字段为null的处理,SQL代码优化
|
*(MAXKEY-201015) mybatis-jpa升级,添加@Entity和@Transient支持,优化update时字段为null的处理,SQL代码优化
|
||||||
*(MAXKEY-201016) README中文和英文支持
|
*(MAXKEY-201016) README更新及中文和英文支持
|
||||||
*(MAXKEY-201017) 认证失败时,authentication 空指针异常
|
*(MAXKEY-201017) 认证失败时,authentication 空指针异常
|
||||||
*(MAXKEY-201018) SAML Metadata URL配置读取
|
*(MAXKEY-201018) SAML Metadata URL配置读取
|
||||||
*(MAXKEY-201020) 依赖jar引用、更新和升级
|
*(MAXKEY-201019) 添加组和角色时按登录名查询成员
|
||||||
|
*(MAXKEY-201020) firefox点击验证码无更新修复
|
||||||
|
*(MAXKEY-201021) 官网内容更新
|
||||||
|
*(MAXKEY-201022) 管理MGT样式调整优化
|
||||||
|
*(MAXKEY-201023) 依赖jar引用、更新和升级
|
||||||
not-yet-commons-ssl 0.3.9
|
not-yet-commons-ssl 0.3.9
|
||||||
log4j 2.14.0
|
log4j 2.14.0
|
||||||
spring 5.3.1
|
spring 5.3.1
|
||||||
@ -26,6 +30,7 @@
|
|||||||
springData 2.4.1
|
springData 2.4.1
|
||||||
springSession 2.4.1
|
springSession 2.4.1
|
||||||
mybatis-jpa-extra 2.2
|
mybatis-jpa-extra 2.2
|
||||||
|
opensaml 2.6.6
|
||||||
|
|
||||||
|
|
||||||
MaxKey v 2.3.0 GA 2020/11/12
|
MaxKey v 2.3.0 GA 2020/11/12
|
||||||
|
|||||||
@ -1,571 +0,0 @@
|
|||||||
package org.apache.commons.ssl;
|
|
||||||
|
|
||||||
import javax.naming.InvalidNameException;
|
|
||||||
import javax.naming.NamingException;
|
|
||||||
import javax.naming.directory.Attribute;
|
|
||||||
import javax.naming.directory.Attributes;
|
|
||||||
import javax.naming.ldap.LdapName;
|
|
||||||
import javax.naming.ldap.Rdn;
|
|
||||||
/*
|
|
||||||
* $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/trunk/src/java/org/apache/commons/ssl/HostnameVerifier.java $
|
|
||||||
* $Revision: 121 $
|
|
||||||
* $Date: 2007-11-14 09:26:57 +0400 (Ср., 14 нояб. 2007) $
|
|
||||||
*
|
|
||||||
* ====================================================================
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
* ====================================================================
|
|
||||||
*
|
|
||||||
* This software consists of voluntary contributions made by many
|
|
||||||
* individuals on behalf of the Apache Software Foundation. For more
|
|
||||||
* information on the Apache Software Foundation, please see
|
|
||||||
* <http://www.apache.org/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
import javax.net.ssl.SSLException;
|
|
||||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
|
||||||
import javax.net.ssl.SSLSession;
|
|
||||||
import javax.net.ssl.SSLSocket;
|
|
||||||
import javax.security.auth.x500.X500Principal;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.security.cert.Certificate;
|
|
||||||
import java.security.cert.CertificateParsingException;
|
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
import java.util.TreeSet;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface for checking if a hostname matches the names stored inside the
|
|
||||||
* server's X.509 certificate. Correctly implements
|
|
||||||
* javax.net.ssl.HostnameVerifier, but that interface is not recommended.
|
|
||||||
* Instead we added several check() methods that take SSLSocket,
|
|
||||||
* or X509Certificate, or ultimately (they all end up calling this one),
|
|
||||||
* String. (It's easier to supply JUnit with Strings instead of mock
|
|
||||||
* SSLSession objects!)
|
|
||||||
* </p><p>Our check() methods throw exceptions if the name is
|
|
||||||
* invalid, whereas javax.net.ssl.HostnameVerifier just returns true/false.
|
|
||||||
* <p/>
|
|
||||||
* We provide the HostnameVerifier.DEFAULT, HostnameVerifier.STRICT, and
|
|
||||||
* HostnameVerifier.ALLOW_ALL implementations. We also provide the more
|
|
||||||
* specialized HostnameVerifier.DEFAULT_AND_LOCALHOST, as well as
|
|
||||||
* HostnameVerifier.STRICT_IE6. But feel free to define your own
|
|
||||||
* implementations!
|
|
||||||
* <p/>
|
|
||||||
* Inspired by Sebastian Hauer's original StrictSSLProtocolSocketFactory in the
|
|
||||||
* HttpClient "contrib" repository.
|
|
||||||
*
|
|
||||||
* @author Julius Davies
|
|
||||||
* @author <a href="mailto:hauer@psicode.com">Sebastian Hauer</a>
|
|
||||||
* @since 8-Dec-2006
|
|
||||||
*/
|
|
||||||
public interface HostnameVerifier extends javax.net.ssl.HostnameVerifier {
|
|
||||||
|
|
||||||
boolean verify(String host, SSLSession session);
|
|
||||||
|
|
||||||
void check(String host, SSLSocket ssl) throws IOException;
|
|
||||||
|
|
||||||
void check(String host, X509Certificate cert) throws SSLException;
|
|
||||||
|
|
||||||
void check(String host, String[] cns, String[] subjectAlts)
|
|
||||||
throws SSLException;
|
|
||||||
|
|
||||||
void check(String[] hosts, SSLSocket ssl) throws IOException;
|
|
||||||
|
|
||||||
void check(String[] hosts, X509Certificate cert) throws SSLException;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks to see if the supplied hostname matches any of the supplied CNs
|
|
||||||
* or "DNS" Subject-Alts. Most implementations only look at the first CN,
|
|
||||||
* and ignore any additional CNs. Most implementations do look at all of
|
|
||||||
* the "DNS" Subject-Alts. The CNs or Subject-Alts may contain wildcards
|
|
||||||
* according to RFC 2818.
|
|
||||||
*
|
|
||||||
* @param cns CN fields, in order, as extracted from the X.509
|
|
||||||
* certificate.
|
|
||||||
* @param subjectAlts Subject-Alt fields of type 2 ("DNS"), as extracted
|
|
||||||
* from the X.509 certificate.
|
|
||||||
* @param hosts The array of hostnames to verify.
|
|
||||||
* @throws SSLException If verification failed.
|
|
||||||
*/
|
|
||||||
void check(String[] hosts, String[] cns, String[] subjectAlts)
|
|
||||||
throws SSLException;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The DEFAULT HostnameVerifier works the same way as Curl and Firefox.
|
|
||||||
* <p/>
|
|
||||||
* The hostname must match either the first CN, or any of the subject-alts.
|
|
||||||
* A wildcard can occur in the CN, and in any of the subject-alts.
|
|
||||||
* <p/>
|
|
||||||
* The only difference between DEFAULT and STRICT is that a wildcard (such
|
|
||||||
* as "*.foo.com") with DEFAULT matches all subdomains, including
|
|
||||||
* "a.b.foo.com".
|
|
||||||
*/
|
|
||||||
public final static HostnameVerifier DEFAULT =
|
|
||||||
new AbstractVerifier() {
|
|
||||||
public final void check(final String[] hosts, final String[] cns,
|
|
||||||
final String[] subjectAlts)
|
|
||||||
throws SSLException {
|
|
||||||
check(hosts, cns, subjectAlts, false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final String toString() { return "DEFAULT"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The DEFAULT_AND_LOCALHOST HostnameVerifier works like the DEFAULT
|
|
||||||
* one with one additional relaxation: a host of "localhost",
|
|
||||||
* "localhost.localdomain", "127.0.0.1", "::1" will always pass, no matter
|
|
||||||
* what is in the server's certificate.
|
|
||||||
*/
|
|
||||||
public final static HostnameVerifier DEFAULT_AND_LOCALHOST =
|
|
||||||
new AbstractVerifier() {
|
|
||||||
public final void check(final String[] hosts, final String[] cns,
|
|
||||||
final String[] subjectAlts)
|
|
||||||
throws SSLException {
|
|
||||||
if (isLocalhost(hosts[0])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
check(hosts, cns, subjectAlts, false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final String toString() { return "DEFAULT_AND_LOCALHOST"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The STRICT HostnameVerifier works the same way as java.net.URL in Sun
|
|
||||||
* Java 1.4, Sun Java 5, Sun Java 6. It's also pretty close to IE6.
|
|
||||||
* This implementation appears to be compliant with RFC 2818 for dealing
|
|
||||||
* with wildcards.
|
|
||||||
* <p/>
|
|
||||||
* The hostname must match either the first CN, or any of the subject-alts.
|
|
||||||
* A wildcard can occur in the CN, and in any of the subject-alts. The
|
|
||||||
* one divergence from IE6 is how we only check the first CN. IE6 allows
|
|
||||||
* a match against any of the CNs present. We decided to follow in
|
|
||||||
* Sun Java 1.4's footsteps and only check the first CN.
|
|
||||||
* <p/>
|
|
||||||
* A wildcard such as "*.foo.com" matches only subdomains in the same
|
|
||||||
* level, for example "a.foo.com". It does not match deeper subdomains
|
|
||||||
* such as "a.b.foo.com".
|
|
||||||
*/
|
|
||||||
public final static HostnameVerifier STRICT =
|
|
||||||
new AbstractVerifier() {
|
|
||||||
public final void check(final String[] host, final String[] cns,
|
|
||||||
final String[] subjectAlts)
|
|
||||||
throws SSLException {
|
|
||||||
check(host, cns, subjectAlts, false, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final String toString() { return "STRICT"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The STRICT_IE6 HostnameVerifier works just like the STRICT one with one
|
|
||||||
* minor variation: the hostname can match against any of the CN's in the
|
|
||||||
* server's certificate, not just the first one. This behaviour is
|
|
||||||
* identical to IE6's behaviour.
|
|
||||||
*/
|
|
||||||
public final static HostnameVerifier STRICT_IE6 =
|
|
||||||
new AbstractVerifier() {
|
|
||||||
public final void check(final String[] host, final String[] cns,
|
|
||||||
final String[] subjectAlts)
|
|
||||||
throws SSLException {
|
|
||||||
check(host, cns, subjectAlts, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final String toString() { return "STRICT_IE6"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The ALLOW_ALL HostnameVerifier essentially turns hostname verification
|
|
||||||
* off. This implementation is a no-op, and never throws the SSLException.
|
|
||||||
*/
|
|
||||||
public final static HostnameVerifier ALLOW_ALL =
|
|
||||||
new AbstractVerifier() {
|
|
||||||
public final void check(final String[] host, final String[] cns,
|
|
||||||
final String[] subjectAlts) {
|
|
||||||
// Allow everything - so never blowup.
|
|
||||||
}
|
|
||||||
|
|
||||||
public final String toString() { return "ALLOW_ALL"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
abstract class AbstractVerifier implements HostnameVerifier {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This contains a list of 2nd-level domains that aren't allowed to
|
|
||||||
* have wildcards when combined with country-codes.
|
|
||||||
* For example: [*.co.uk].
|
|
||||||
* <p/>
|
|
||||||
* The [*.co.uk] problem is an interesting one. Should we just hope
|
|
||||||
* that CA's would never foolishly allow such a certificate to happen?
|
|
||||||
* Looks like we're the only implementation guarding against this.
|
|
||||||
* Firefox, Curl, Sun Java 1.4, 5, 6 don't bother with this check.
|
|
||||||
*/
|
|
||||||
private final static String[] BAD_COUNTRY_2LDS =
|
|
||||||
{"ac", "co", "com", "ed", "edu", "go", "gouv", "gov", "info",
|
|
||||||
"lg", "ne", "net", "or", "org"};
|
|
||||||
|
|
||||||
private final static String[] LOCALHOSTS = {"::1", "127.0.0.1",
|
|
||||||
"localhost",
|
|
||||||
"localhost.localdomain"};
|
|
||||||
|
|
||||||
|
|
||||||
static {
|
|
||||||
// Just in case developer forgot to manually sort the array. :-)
|
|
||||||
Arrays.sort(BAD_COUNTRY_2LDS);
|
|
||||||
Arrays.sort(LOCALHOSTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected AbstractVerifier() {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The javax.net.ssl.HostnameVerifier contract.
|
|
||||||
*
|
|
||||||
* @param host 'hostname' we used to create our socket
|
|
||||||
* @param session SSLSession with the remote server
|
|
||||||
* @return true if the host matched the one in the certificate.
|
|
||||||
*/
|
|
||||||
public boolean verify(String host, SSLSession session) {
|
|
||||||
try {
|
|
||||||
Certificate[] certs = session.getPeerCertificates();
|
|
||||||
X509Certificate x509 = (X509Certificate) certs[0];
|
|
||||||
check(new String[]{host}, x509);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (SSLException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void check(String host, SSLSocket ssl) throws IOException {
|
|
||||||
check(new String[]{host}, ssl);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void check(String host, X509Certificate cert)
|
|
||||||
throws SSLException {
|
|
||||||
check(new String[]{host}, cert);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void check(String host, String[] cns, String[] subjectAlts)
|
|
||||||
throws SSLException {
|
|
||||||
check(new String[]{host}, cns, subjectAlts);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void check(String host[], SSLSocket ssl)
|
|
||||||
throws IOException {
|
|
||||||
if (host == null) {
|
|
||||||
throw new NullPointerException("host to verify is null");
|
|
||||||
}
|
|
||||||
|
|
||||||
SSLSession session = ssl.getSession();
|
|
||||||
if (session == null) {
|
|
||||||
// In our experience this only happens under IBM 1.4.x when
|
|
||||||
// spurious (unrelated) certificates show up in the server'
|
|
||||||
// chain. Hopefully this will unearth the real problem:
|
|
||||||
InputStream in = ssl.getInputStream();
|
|
||||||
in.available();
|
|
||||||
/*
|
|
||||||
If you're looking at the 2 lines of code above because
|
|
||||||
you're running into a problem, you probably have two
|
|
||||||
options:
|
|
||||||
#1. Clean up the certificate chain that your server
|
|
||||||
is presenting (e.g. edit "/etc/apache2/server.crt"
|
|
||||||
or wherever it is your server's certificate chain
|
|
||||||
is defined).
|
|
||||||
OR
|
|
||||||
#2. Upgrade to an IBM 1.5.x or greater JVM, or switch
|
|
||||||
to a non-IBM JVM.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// If ssl.getInputStream().available() didn't cause an
|
|
||||||
// exception, maybe at least now the session is available?
|
|
||||||
session = ssl.getSession();
|
|
||||||
if (session == null) {
|
|
||||||
// If it's still null, probably a startHandshake() will
|
|
||||||
// unearth the real problem.
|
|
||||||
ssl.startHandshake();
|
|
||||||
|
|
||||||
// Okay, if we still haven't managed to cause an exception,
|
|
||||||
// might as well go for the NPE. Or maybe we're okay now?
|
|
||||||
session = ssl.getSession();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Certificate[] certs;
|
|
||||||
try {
|
|
||||||
certs = session.getPeerCertificates();
|
|
||||||
} catch (SSLPeerUnverifiedException spue) {
|
|
||||||
InputStream in = ssl.getInputStream();
|
|
||||||
in.available();
|
|
||||||
// Didn't trigger anything interesting? Okay, just throw
|
|
||||||
// original.
|
|
||||||
throw spue;
|
|
||||||
}
|
|
||||||
X509Certificate x509 = (X509Certificate) certs[0];
|
|
||||||
check(host, x509);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void check(String[] host, X509Certificate cert)
|
|
||||||
throws SSLException {
|
|
||||||
String[] cns = getCNs(cert);
|
|
||||||
String[] subjectAlts = getDNSSubjectAlts(cert);
|
|
||||||
check(host, cns, subjectAlts);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void check(final String[] hosts, final String[] cns,
|
|
||||||
final String[] subjectAlts, final boolean ie6,
|
|
||||||
final boolean strictWithSubDomains)
|
|
||||||
throws SSLException {
|
|
||||||
// Build up lists of allowed hosts For logging/debugging purposes.
|
|
||||||
StringBuffer buf = new StringBuffer(32);
|
|
||||||
buf.append('<');
|
|
||||||
for (int i = 0; i < hosts.length; i++) {
|
|
||||||
String h = hosts[i];
|
|
||||||
h = h != null ? h.trim().toLowerCase() : "";
|
|
||||||
hosts[i] = h;
|
|
||||||
if (i > 0) {
|
|
||||||
buf.append('/');
|
|
||||||
}
|
|
||||||
buf.append(h);
|
|
||||||
}
|
|
||||||
buf.append('>');
|
|
||||||
String hostnames = buf.toString();
|
|
||||||
// Build the list of names we're going to check. Our DEFAULT and
|
|
||||||
// STRICT implementations of the HostnameVerifier only use the
|
|
||||||
// first CN provided. All other CNs are ignored.
|
|
||||||
// (Firefox, wget, curl, Sun Java 1.4, 5, 6 all work this way).
|
|
||||||
TreeSet names = new TreeSet();
|
|
||||||
if (cns != null && cns.length > 0 && cns[0] != null) {
|
|
||||||
names.add(cns[0]);
|
|
||||||
if (ie6) {
|
|
||||||
for (int i = 1; i < cns.length; i++) {
|
|
||||||
names.add(cns[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (subjectAlts != null) {
|
|
||||||
for (int i = 0; i < subjectAlts.length; i++) {
|
|
||||||
if (subjectAlts[i] != null) {
|
|
||||||
names.add(subjectAlts[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (names.isEmpty()) {
|
|
||||||
String msg = "Certificate for " + hosts[0] + " doesn't contain CN or DNS subjectAlt";
|
|
||||||
throw new SSLException(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
// StringBuffer for building the error message.
|
|
||||||
buf = new StringBuffer();
|
|
||||||
|
|
||||||
boolean match = false;
|
|
||||||
out:
|
|
||||||
for (Iterator it = names.iterator(); it.hasNext();) {
|
|
||||||
// Don't trim the CN, though!
|
|
||||||
String cn = (String) it.next();
|
|
||||||
cn = cn.toLowerCase();
|
|
||||||
// Store CN in StringBuffer in case we need to report an error.
|
|
||||||
buf.append(" <");
|
|
||||||
buf.append(cn);
|
|
||||||
buf.append('>');
|
|
||||||
if (it.hasNext()) {
|
|
||||||
buf.append(" OR");
|
|
||||||
}
|
|
||||||
|
|
||||||
// The CN better have at least two dots if it wants wildcard
|
|
||||||
// action. It also can't be [*.co.uk] or [*.co.jp] or
|
|
||||||
// [*.org.uk], etc...
|
|
||||||
boolean doWildcard = cn.startsWith("*.") &&
|
|
||||||
cn.lastIndexOf('.') >= 0 &&
|
|
||||||
!isIP4Address(cn) &&
|
|
||||||
acceptableCountryWildcard(cn);
|
|
||||||
|
|
||||||
for (int i = 0; i < hosts.length; i++) {
|
|
||||||
final String hostName = hosts[i].trim().toLowerCase();
|
|
||||||
if (doWildcard) {
|
|
||||||
match = hostName.endsWith(cn.substring(1));
|
|
||||||
if (match && strictWithSubDomains) {
|
|
||||||
// If we're in strict mode, then [*.foo.com] is not
|
|
||||||
// allowed to match [a.b.foo.com]
|
|
||||||
match = countDots(hostName) == countDots(cn);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
match = hostName.equals(cn);
|
|
||||||
}
|
|
||||||
if (match) {
|
|
||||||
break out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!match) {
|
|
||||||
throw new SSLException("hostname in certificate didn't match: " + hostnames + " !=" + buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isIP4Address(final String cn) {
|
|
||||||
boolean isIP4 = true;
|
|
||||||
String tld = cn;
|
|
||||||
int x = cn.lastIndexOf('.');
|
|
||||||
// We only bother analyzing the characters after the final dot
|
|
||||||
// in the name.
|
|
||||||
if (x >= 0 && x + 1 < cn.length()) {
|
|
||||||
tld = cn.substring(x + 1);
|
|
||||||
}
|
|
||||||
for (int i = 0; i < tld.length(); i++) {
|
|
||||||
if (!Character.isDigit(tld.charAt(0))) {
|
|
||||||
isIP4 = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return isIP4;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean acceptableCountryWildcard(final String cn) {
|
|
||||||
int cnLen = cn.length();
|
|
||||||
if (cnLen >= 7 && cnLen <= 9) {
|
|
||||||
// Look for the '.' in the 3rd-last position:
|
|
||||||
if (cn.charAt(cnLen - 3) == '.') {
|
|
||||||
// Trim off the [*.] and the [.XX].
|
|
||||||
String s = cn.substring(2, cnLen - 3);
|
|
||||||
// And test against the sorted array of bad 2lds:
|
|
||||||
int x = Arrays.binarySearch(BAD_COUNTRY_2LDS, s);
|
|
||||||
return x < 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isLocalhost(String host) {
|
|
||||||
host = host != null ? host.trim().toLowerCase() : "";
|
|
||||||
if (host.startsWith("::1")) {
|
|
||||||
int x = host.lastIndexOf('%');
|
|
||||||
if (x >= 0) {
|
|
||||||
host = host.substring(0, x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int x = Arrays.binarySearch(LOCALHOSTS, host);
|
|
||||||
return x >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Counts the number of dots "." in a string.
|
|
||||||
*
|
|
||||||
* @param s string to count dots from
|
|
||||||
* @return number of dots
|
|
||||||
*/
|
|
||||||
public static int countDots(final String s) {
|
|
||||||
int count = 0;
|
|
||||||
for (int i = 0; i < s.length(); i++) {
|
|
||||||
if (s.charAt(i) == '.') {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//from Certificate
|
|
||||||
public static String getCN(X509Certificate cert) {
|
|
||||||
String[] cns = getCNs(cert);
|
|
||||||
boolean foundSomeCNs = cns != null && cns.length >= 1;
|
|
||||||
return foundSomeCNs ? cns[0] : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String[] getCNs(X509Certificate cert) {
|
|
||||||
try {
|
|
||||||
final String subjectPrincipal = cert.getSubjectX500Principal().getName(X500Principal.RFC2253);
|
|
||||||
final LinkedList<String> cnList = new LinkedList<String>();
|
|
||||||
final LdapName subjectDN = new LdapName(subjectPrincipal);
|
|
||||||
for (final Rdn rds : subjectDN.getRdns()) {
|
|
||||||
final Attributes attributes = rds.toAttributes();
|
|
||||||
final Attribute cn = attributes.get("cn");
|
|
||||||
if (cn != null) {
|
|
||||||
try {
|
|
||||||
final Object value = cn.get();
|
|
||||||
if (value != null) {
|
|
||||||
cnList.add(value.toString());
|
|
||||||
}
|
|
||||||
} catch (NoSuchElementException ignore) {
|
|
||||||
} catch (NamingException ignore) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!cnList.isEmpty()) {
|
|
||||||
return cnList.toArray(new String[cnList.size()]);
|
|
||||||
}
|
|
||||||
} catch (InvalidNameException ignore) {
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extracts the array of SubjectAlt DNS names from an X509Certificate.
|
|
||||||
* Returns null if there aren't any.
|
|
||||||
* <p/>
|
|
||||||
* Note: Java doesn't appear able to extract international characters
|
|
||||||
* from the SubjectAlts. It can only extract international characters
|
|
||||||
* from the CN field.
|
|
||||||
* <p/>
|
|
||||||
* (Or maybe the version of OpenSSL I'm using to test isn't storing the
|
|
||||||
* international characters correctly in the SubjectAlts?).
|
|
||||||
*
|
|
||||||
* @param cert X509Certificate
|
|
||||||
* @return Array of SubjectALT DNS names stored in the certificate.
|
|
||||||
*/
|
|
||||||
public static String[] getDNSSubjectAlts(X509Certificate cert) {
|
|
||||||
LinkedList subjectAltList = new LinkedList();
|
|
||||||
Collection c = null;
|
|
||||||
try {
|
|
||||||
c = cert.getSubjectAlternativeNames();
|
|
||||||
}
|
|
||||||
catch (CertificateParsingException cpe) {
|
|
||||||
// Should probably log.debug() this?
|
|
||||||
cpe.printStackTrace();
|
|
||||||
}
|
|
||||||
if (c != null) {
|
|
||||||
Iterator it = c.iterator();
|
|
||||||
while (it.hasNext()) {
|
|
||||||
List list = (List) it.next();
|
|
||||||
int type = ((Integer) list.get(0)).intValue();
|
|
||||||
// If type is 2, then we've got a dNSName
|
|
||||||
if (type == 2) {
|
|
||||||
String s = (String) list.get(1);
|
|
||||||
subjectAltList.add(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!subjectAltList.isEmpty()) {
|
|
||||||
String[] subjectAlts = new String[subjectAltList.size()];
|
|
||||||
subjectAltList.toArray(subjectAlts);
|
|
||||||
return subjectAlts;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -188,6 +188,12 @@ public class Groups extends JpaBaseDomain implements Serializable {
|
|||||||
builder.append(id);
|
builder.append(id);
|
||||||
builder.append(", name=");
|
builder.append(", name=");
|
||||||
builder.append(name);
|
builder.append(name);
|
||||||
|
builder.append(", dynamic=");
|
||||||
|
builder.append(dynamic);
|
||||||
|
builder.append(", filters=");
|
||||||
|
builder.append(filters);
|
||||||
|
builder.append(", orgIdsList=");
|
||||||
|
builder.append(orgIdsList);
|
||||||
builder.append(", isdefault=");
|
builder.append(", isdefault=");
|
||||||
builder.append(isdefault);
|
builder.append(isdefault);
|
||||||
builder.append(", description=");
|
builder.append(", description=");
|
||||||
|
|||||||
@ -38,6 +38,14 @@ public class Roles extends JpaBaseDomain implements Serializable {
|
|||||||
@Column
|
@Column
|
||||||
private String name;
|
private String name;
|
||||||
@Column
|
@Column
|
||||||
|
String dynamic;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
String filters ;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
String orgIdsList;
|
||||||
|
@Column
|
||||||
String status;
|
String status;
|
||||||
@Column
|
@Column
|
||||||
String description;
|
String description;
|
||||||
@ -119,6 +127,30 @@ public class Roles extends JpaBaseDomain implements Serializable {
|
|||||||
this.modifiedDate = modifiedDate;
|
this.modifiedDate = modifiedDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getDynamic() {
|
||||||
|
return dynamic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDynamic(String dynamic) {
|
||||||
|
this.dynamic = dynamic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFilters() {
|
||||||
|
return filters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFilters(String filters) {
|
||||||
|
this.filters = filters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOrgIdsList() {
|
||||||
|
return orgIdsList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrgIdsList(String orgIdsList) {
|
||||||
|
this.orgIdsList = orgIdsList;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
@ -126,6 +158,12 @@ public class Roles extends JpaBaseDomain implements Serializable {
|
|||||||
builder.append(id);
|
builder.append(id);
|
||||||
builder.append(", name=");
|
builder.append(", name=");
|
||||||
builder.append(name);
|
builder.append(name);
|
||||||
|
builder.append(", dynamic=");
|
||||||
|
builder.append(dynamic);
|
||||||
|
builder.append(", filters=");
|
||||||
|
builder.append(filters);
|
||||||
|
builder.append(", orgIdsList=");
|
||||||
|
builder.append(orgIdsList);
|
||||||
builder.append(", status=");
|
builder.append(", status=");
|
||||||
builder.append(status);
|
builder.append(status);
|
||||||
builder.append(", description=");
|
builder.append(", description=");
|
||||||
|
|||||||
@ -518,4 +518,33 @@ public final class StringUtils {
|
|||||||
return flag;
|
return flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ArrayList<String> sqlInjection = null;
|
||||||
|
|
||||||
|
static{
|
||||||
|
sqlInjection = new ArrayList<String>();
|
||||||
|
sqlInjection.add("--");
|
||||||
|
sqlInjection.add(";");
|
||||||
|
sqlInjection.add("/");
|
||||||
|
sqlInjection.add("\\");
|
||||||
|
sqlInjection.add("#");
|
||||||
|
sqlInjection.add("drop");
|
||||||
|
sqlInjection.add("create");
|
||||||
|
sqlInjection.add("delete");
|
||||||
|
sqlInjection.add("alter");
|
||||||
|
sqlInjection.add("truncate");
|
||||||
|
sqlInjection.add("update");
|
||||||
|
sqlInjection.add("insert");
|
||||||
|
sqlInjection.add("and");
|
||||||
|
sqlInjection.add("or");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean filtersSQLInjection(String filters) {
|
||||||
|
for(String s : sqlInjection) {
|
||||||
|
if(filters.indexOf(s)>-1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,6 +62,10 @@ public class InitializeContext extends HttpServlet {
|
|||||||
_logger.info("SecurityContextHolder StrategyName " + SessionSecurityContextHolderStrategy.class.getCanonicalName());
|
_logger.info("SecurityContextHolder StrategyName " + SessionSecurityContextHolderStrategy.class.getCanonicalName());
|
||||||
SecurityContextHolder.setStrategyName(SessionSecurityContextHolderStrategy.class.getCanonicalName());
|
SecurityContextHolder.setStrategyName(SessionSecurityContextHolderStrategy.class.getCanonicalName());
|
||||||
|
|
||||||
|
WebContext.applicationContext = applicationContext;
|
||||||
|
|
||||||
|
org.apache.mybatis.jpa.util.WebContext.applicationContext = applicationContext;
|
||||||
|
|
||||||
// List Environment Variables
|
// List Environment Variables
|
||||||
listEnvVars();
|
listEnvVars();
|
||||||
|
|
||||||
|
|||||||
@ -57,6 +57,8 @@ public final class WebContext {
|
|||||||
|
|
||||||
public static Properties properties;
|
public static Properties properties;
|
||||||
|
|
||||||
|
public static ApplicationContext applicationContext;
|
||||||
|
|
||||||
public static ArrayList<String> sessionAttributeNameList = new ArrayList<String>();
|
public static ArrayList<String> sessionAttributeNameList = new ArrayList<String>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@ -137,23 +139,24 @@ public final class WebContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get ApplicationContext from web ServletContext configuration.
|
* get ApplicationContext from web ServletContext configuration
|
||||||
*
|
|
||||||
* @return ApplicationContext
|
* @return ApplicationContext
|
||||||
*/
|
*/
|
||||||
public static ApplicationContext getApplicationContext() {
|
public static ApplicationContext getApplicationContext(){
|
||||||
return WebApplicationContextUtils.getWebApplicationContext(
|
return WebApplicationContextUtils.getWebApplicationContext(getSession().getServletContext());
|
||||||
getSession().getServletContext());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get bean from spring configuration by bean id.
|
* get bean from spring configuration by bean id
|
||||||
*
|
* @param id
|
||||||
* @param id String
|
|
||||||
* @return Object
|
* @return Object
|
||||||
*/
|
*/
|
||||||
public static Object getBean(String id) {
|
public static Object getBean(String id){
|
||||||
return getApplicationContext().getBean(id);
|
if(applicationContext==null) {
|
||||||
|
return getApplicationContext().getBean(id);
|
||||||
|
}else {
|
||||||
|
return applicationContext.getBean(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// below method is common HttpServlet method
|
// below method is common HttpServlet method
|
||||||
|
|||||||
@ -24,6 +24,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import org.apache.mybatis.jpa.persistence.IJpaBaseMapper;
|
import org.apache.mybatis.jpa.persistence.IJpaBaseMapper;
|
||||||
import org.maxkey.domain.GroupMember;
|
import org.maxkey.domain.GroupMember;
|
||||||
|
import org.maxkey.domain.Groups;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Crystal.sea
|
* @author Crystal.sea
|
||||||
@ -36,4 +37,13 @@ public interface GroupMemberMapper extends IJpaBaseMapper<GroupMember> {
|
|||||||
public List<GroupMember> memberInGroup(GroupMember entity);
|
public List<GroupMember> memberInGroup(GroupMember entity);
|
||||||
public List<GroupMember> memberNotInGroup(GroupMember entity);
|
public List<GroupMember> memberNotInGroup(GroupMember entity);
|
||||||
public List<GroupMember> groupMemberInGroup(GroupMember entity);
|
public List<GroupMember> groupMemberInGroup(GroupMember entity);
|
||||||
|
|
||||||
|
public int addDynamicGroupMember(Groups dynamicGroup);
|
||||||
|
|
||||||
|
public int deleteDynamicGroupMember(Groups dynamicGroup);
|
||||||
|
|
||||||
|
public int deleteByGroupId(String groupId);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,6 +20,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.maxkey.persistence.mapper;
|
package org.maxkey.persistence.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.mybatis.jpa.persistence.IJpaBaseMapper;
|
import org.apache.mybatis.jpa.persistence.IJpaBaseMapper;
|
||||||
import org.maxkey.domain.Groups;
|
import org.maxkey.domain.Groups;
|
||||||
|
|
||||||
@ -30,4 +32,5 @@ import org.maxkey.domain.Groups;
|
|||||||
|
|
||||||
public interface GroupsMapper extends IJpaBaseMapper<Groups> {
|
public interface GroupsMapper extends IJpaBaseMapper<Groups> {
|
||||||
|
|
||||||
|
public List<Groups> queryDynamicGroups(Groups groups);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,6 +24,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import org.apache.mybatis.jpa.persistence.IJpaBaseMapper;
|
import org.apache.mybatis.jpa.persistence.IJpaBaseMapper;
|
||||||
import org.maxkey.domain.RoleMember;
|
import org.maxkey.domain.RoleMember;
|
||||||
|
import org.maxkey.domain.Roles;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Crystal.sea
|
* @author Crystal.sea
|
||||||
@ -36,4 +37,10 @@ public interface RoleMemberMapper extends IJpaBaseMapper<RoleMember> {
|
|||||||
public List<RoleMember> memberInRole(RoleMember entity);
|
public List<RoleMember> memberInRole(RoleMember entity);
|
||||||
public List<RoleMember> memberNotInRole(RoleMember entity);
|
public List<RoleMember> memberNotInRole(RoleMember entity);
|
||||||
public List<RoleMember> roleMemberInRole(RoleMember entity);
|
public List<RoleMember> roleMemberInRole(RoleMember entity);
|
||||||
|
|
||||||
|
public int addDynamicRoleMember(Roles dynamicRole);
|
||||||
|
|
||||||
|
public int deleteDynamicRoleMember(Roles dynamicRole);
|
||||||
|
|
||||||
|
public int deleteByRoleId(String roleId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,4 +38,6 @@ public interface RolesMapper extends IJpaBaseMapper<Roles> {
|
|||||||
public int logisticDeleteRolePermissions(List<RolePermissions> rolePermissionsList);
|
public int logisticDeleteRolePermissions(List<RolePermissions> rolePermissionsList);
|
||||||
|
|
||||||
public List<RolePermissions> queryRolePermissions(RolePermissions rolePermissions);
|
public List<RolePermissions> queryRolePermissions(RolePermissions rolePermissions);
|
||||||
|
|
||||||
|
public List<Roles> queryDynamicRoles(Roles role);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,6 +19,7 @@ package org.maxkey.persistence.service;
|
|||||||
|
|
||||||
import org.apache.mybatis.jpa.persistence.JpaBaseService;
|
import org.apache.mybatis.jpa.persistence.JpaBaseService;
|
||||||
import org.maxkey.domain.GroupMember;
|
import org.maxkey.domain.GroupMember;
|
||||||
|
import org.maxkey.domain.Groups;
|
||||||
import org.maxkey.persistence.mapper.GroupMemberMapper;
|
import org.maxkey.persistence.mapper.GroupMemberMapper;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@ -37,4 +38,16 @@ public class GroupMemberService extends JpaBaseService<GroupMember>{
|
|||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
return (GroupMemberMapper)super.getMapper();
|
return (GroupMemberMapper)super.getMapper();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int addDynamicGroupMember(Groups dynamicGroup) {
|
||||||
|
return getMapper().addDynamicGroupMember(dynamicGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int deleteDynamicGroupMember(Groups dynamicGroup) {
|
||||||
|
return getMapper().deleteDynamicGroupMember(dynamicGroup);
|
||||||
|
}
|
||||||
|
public int deleteByGroupId(String groupId) {
|
||||||
|
return getMapper().deleteByGroupId(groupId);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,14 +17,25 @@
|
|||||||
|
|
||||||
package org.maxkey.persistence.service;
|
package org.maxkey.persistence.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.mybatis.jpa.persistence.JpaBaseService;
|
import org.apache.mybatis.jpa.persistence.JpaBaseService;
|
||||||
import org.maxkey.domain.Groups;
|
import org.maxkey.domain.Groups;
|
||||||
import org.maxkey.persistence.mapper.GroupsMapper;
|
import org.maxkey.persistence.mapper.GroupsMapper;
|
||||||
|
import org.maxkey.util.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class GroupsService extends JpaBaseService<Groups>{
|
public class GroupsService extends JpaBaseService<Groups>{
|
||||||
|
final static Logger _logger = LoggerFactory.getLogger(GroupsService.class);
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("groupMemberService")
|
||||||
|
GroupMemberService groupMemberService;
|
||||||
|
|
||||||
public GroupsService() {
|
public GroupsService() {
|
||||||
super(GroupsMapper.class);
|
super(GroupsMapper.class);
|
||||||
}
|
}
|
||||||
@ -37,4 +48,39 @@ public class GroupsService extends JpaBaseService<Groups>{
|
|||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
return (GroupsMapper)super.getMapper();
|
return (GroupsMapper)super.getMapper();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public List<Groups> queryDynamicGroups(Groups groups){
|
||||||
|
return this.getMapper().queryDynamicGroups(groups);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean deleteById(String groupId) {
|
||||||
|
this.remove(groupId);
|
||||||
|
groupMemberService.deleteByGroupId(groupId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void refreshDynamicGroups(Groups dynamicGroup){
|
||||||
|
if(dynamicGroup.getDynamic().equals("1")) {
|
||||||
|
if(dynamicGroup.getOrgIdsList()!=null && !dynamicGroup.getOrgIdsList().equals("")) {
|
||||||
|
dynamicGroup.setOrgIdsList("'"+dynamicGroup.getOrgIdsList().replace(",", "','")+"'");
|
||||||
|
}
|
||||||
|
String filters = dynamicGroup.getFilters();
|
||||||
|
if(StringUtils.filtersSQLInjection(filters.toLowerCase())) {
|
||||||
|
_logger.info("filters include SQL Injection Attack Risk.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
filters = filters.replace("&", " AND ");
|
||||||
|
filters = filters.replace("|", " OR ");
|
||||||
|
|
||||||
|
dynamicGroup.setFilters(filters);
|
||||||
|
|
||||||
|
groupMemberService.deleteDynamicGroupMember(dynamicGroup);
|
||||||
|
groupMemberService.addDynamicGroupMember(dynamicGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,6 +19,7 @@ package org.maxkey.persistence.service;
|
|||||||
|
|
||||||
import org.apache.mybatis.jpa.persistence.JpaBaseService;
|
import org.apache.mybatis.jpa.persistence.JpaBaseService;
|
||||||
import org.maxkey.domain.RoleMember;
|
import org.maxkey.domain.RoleMember;
|
||||||
|
import org.maxkey.domain.Roles;
|
||||||
import org.maxkey.persistence.mapper.RoleMemberMapper;
|
import org.maxkey.persistence.mapper.RoleMemberMapper;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@ -37,4 +38,17 @@ public class RoleMemberService extends JpaBaseService<RoleMember>{
|
|||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
return (RoleMemberMapper)super.getMapper();
|
return (RoleMemberMapper)super.getMapper();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public int addDynamicRoleMember(Roles dynamicRole) {
|
||||||
|
return getMapper().addDynamicRoleMember(dynamicRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int deleteDynamicRoleMember(Roles dynamicRole) {
|
||||||
|
return getMapper().deleteDynamicRoleMember(dynamicRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int deleteByRoleId(String roleId) {
|
||||||
|
return getMapper().deleteByRoleId(roleId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,11 +23,21 @@ import org.apache.mybatis.jpa.persistence.JpaBaseService;
|
|||||||
import org.maxkey.domain.RolePermissions;
|
import org.maxkey.domain.RolePermissions;
|
||||||
import org.maxkey.domain.Roles;
|
import org.maxkey.domain.Roles;
|
||||||
import org.maxkey.persistence.mapper.RolesMapper;
|
import org.maxkey.persistence.mapper.RolesMapper;
|
||||||
|
import org.maxkey.util.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class RolesService extends JpaBaseService<Roles>{
|
public class RolesService extends JpaBaseService<Roles>{
|
||||||
|
final static Logger _logger = LoggerFactory.getLogger(RolesService.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("roleMemberService")
|
||||||
|
RoleMemberService roleMemberService;
|
||||||
|
|
||||||
public RolesService() {
|
public RolesService() {
|
||||||
super(RolesMapper.class);
|
super(RolesMapper.class);
|
||||||
}
|
}
|
||||||
@ -51,4 +61,36 @@ public class RolesService extends JpaBaseService<Roles>{
|
|||||||
public List<RolePermissions> queryRolePermissions(RolePermissions rolePermissions){
|
public List<RolePermissions> queryRolePermissions(RolePermissions rolePermissions){
|
||||||
return getMapper().queryRolePermissions(rolePermissions);
|
return getMapper().queryRolePermissions(rolePermissions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Roles> queryDynamicRoles(Roles dynamicRole){
|
||||||
|
return this.getMapper().queryDynamicRoles(dynamicRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean deleteById(String roleId) {
|
||||||
|
this.remove(roleId);
|
||||||
|
roleMemberService.deleteByRoleId(roleId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void refreshDynamicRoles(Roles dynamicRole){
|
||||||
|
if(dynamicRole.getDynamic().equals("1")) {
|
||||||
|
if(dynamicRole.getOrgIdsList()!=null && !dynamicRole.getOrgIdsList().equals("")) {
|
||||||
|
dynamicRole.setOrgIdsList("'"+dynamicRole.getOrgIdsList().replace(",", "','")+"'");
|
||||||
|
}
|
||||||
|
|
||||||
|
String filters = dynamicRole.getFilters();
|
||||||
|
if(StringUtils.filtersSQLInjection(filters.toLowerCase())) {
|
||||||
|
_logger.info("filters include SQL Injection Attack Risk.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
filters = filters.replace("&", " AND ");
|
||||||
|
filters = filters.replace("|", " OR ");
|
||||||
|
|
||||||
|
dynamicRole.setFilters(filters);
|
||||||
|
|
||||||
|
roleMemberService.deleteDynamicRoleMember(dynamicRole);
|
||||||
|
roleMemberService.addDynamicRoleMember(dynamicRole);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -108,7 +108,13 @@
|
|||||||
<if test="groupName != null and groupName != ''">
|
<if test="groupName != null and groupName != ''">
|
||||||
AND G.NAME = #{groupName}
|
AND G.NAME = #{groupName}
|
||||||
</if>
|
</if>
|
||||||
AND GM.TYPE = 'USER'
|
<if test="username != null and username != ''">
|
||||||
|
AND U.USERNAME = #{username}
|
||||||
|
</if>
|
||||||
|
<if test="displayName != null and displayName != ''">
|
||||||
|
AND U.DISPLAYNAME LIKE '%${displayName}%'
|
||||||
|
</if>
|
||||||
|
AND GM.TYPE IN( 'USER','USER-DYNAMIC')
|
||||||
AND GM.GROUPID = G.ID
|
AND GM.GROUPID = G.ID
|
||||||
AND GM.MEMBERID = U.ID
|
AND GM.MEMBERID = U.ID
|
||||||
</select>
|
</select>
|
||||||
@ -167,9 +173,15 @@
|
|||||||
<if test="groupName != null and groupName != ''">
|
<if test="groupName != null and groupName != ''">
|
||||||
AND G.NAME = #{groupName}
|
AND G.NAME = #{groupName}
|
||||||
</if>
|
</if>
|
||||||
AND GM.TYPE = 'USER'
|
AND GM.TYPE IN( 'USER','USER-DYNAMIC')
|
||||||
AND GM.GROUPID = G.ID
|
AND GM.GROUPID = G.ID
|
||||||
)
|
)
|
||||||
|
<if test="username != null and username != ''">
|
||||||
|
AND U.USERNAME = #{username}
|
||||||
|
</if>
|
||||||
|
<if test="displayName != null and displayName != ''">
|
||||||
|
AND U.DISPLAYNAME LIKE '%${displayName}%'
|
||||||
|
</if>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
|
||||||
@ -195,5 +207,54 @@
|
|||||||
</if>
|
</if>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<update id="addDynamicGroupMember" parameterType="Groups" >
|
||||||
|
INSERT INTO MXK_GROUP_MEMBER(
|
||||||
|
ID,
|
||||||
|
GROUPID,
|
||||||
|
MEMBERID,
|
||||||
|
TYPE
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
CONCAT_WS('-','UD','${id}',U.ID) ID,
|
||||||
|
'${id}' GROUPID,
|
||||||
|
U.ID MEMBERID,
|
||||||
|
'USER-DYNAMIC' TYPE
|
||||||
|
FROM MXK_USERINFO U
|
||||||
|
WHERE NOT EXISTS(
|
||||||
|
SELECT 1 FROM MXK_GROUP_MEMBER GM
|
||||||
|
WHERE GM.GROUPID=#{id}
|
||||||
|
AND GM.MEMBERID=U.ID
|
||||||
|
AND GM.TYPE='USER-DYNAMIC'
|
||||||
|
)
|
||||||
|
<if test="filters != null and filters != ''">
|
||||||
|
AND (${filters})
|
||||||
|
</if>
|
||||||
|
<if test="orgIdsList != null and orgIdsList != ''">
|
||||||
|
AND U.DEPARTMENTID IN( ${orgIdsList})
|
||||||
|
</if>
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<delete id="deleteDynamicGroupMember" parameterType="Groups" >
|
||||||
|
DELETE FROM MXK_GROUP_MEMBER GM
|
||||||
|
WHERE TYPE = 'USER-DYNAMIC'
|
||||||
|
AND GM.GROUPID=#{id}
|
||||||
|
AND NOT EXISTS(
|
||||||
|
SELECT 1
|
||||||
|
FROM MXK_USERINFO U
|
||||||
|
WHERE 1 = 1
|
||||||
|
AND U.ID=GM.MEMBERID
|
||||||
|
<if test="filters != null and filters != ''">
|
||||||
|
AND (${filters})
|
||||||
|
</if>
|
||||||
|
<if test="orgIdsList != null and orgIdsList != ''">
|
||||||
|
AND U.DEPARTMENTID IN ( ${orgIdsList})
|
||||||
|
</if>
|
||||||
|
)
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
<delete id="deleteByGroupId" parameterType="string" >
|
||||||
|
DELETE FROM MXK_GROUP_MEMBER GM
|
||||||
|
WHERE GM.GROUPID=#{value}
|
||||||
|
</delete>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
@ -23,6 +23,16 @@
|
|||||||
<include refid="where_statement"/>
|
<include refid="where_statement"/>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="queryDynamicGroups" parameterType="Groups" resultType="Groups">
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
`MXK_GROUPS`
|
||||||
|
WHERE
|
||||||
|
DYNAMIC = '1'
|
||||||
|
<include refid="where_statement"/>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
|
||||||
<update id="logisticDelete" parameterType="Groups" >
|
<update id="logisticDelete" parameterType="Groups" >
|
||||||
UPDATE `MXK_GROUPS` SET
|
UPDATE `MXK_GROUPS` SET
|
||||||
|
|||||||
@ -108,7 +108,13 @@
|
|||||||
<if test="roleName != null and roleName != ''">
|
<if test="roleName != null and roleName != ''">
|
||||||
AND R.NAME = #{roleName}
|
AND R.NAME = #{roleName}
|
||||||
</if>
|
</if>
|
||||||
AND RM.TYPE = 'USER'
|
<if test="username != null and username != ''">
|
||||||
|
AND U.USERNAME = #{username}
|
||||||
|
</if>
|
||||||
|
<if test="displayName != null and displayName != ''">
|
||||||
|
AND U.DISPLAYNAME LIKE '%${displayName}%'
|
||||||
|
</if>
|
||||||
|
AND RM.TYPE IN( 'USER','USER-DYNAMIC')
|
||||||
AND RM.ROLEID = R.ID
|
AND RM.ROLEID = R.ID
|
||||||
AND RM.MEMBERID = U.ID
|
AND RM.MEMBERID = U.ID
|
||||||
</select>
|
</select>
|
||||||
@ -167,14 +173,21 @@
|
|||||||
<if test="roleName != null and roleName != ''">
|
<if test="roleName != null and roleName != ''">
|
||||||
AND R.NAME = #{roleName}
|
AND R.NAME = #{roleName}
|
||||||
</if>
|
</if>
|
||||||
AND RM.TYPE = 'USER'
|
|
||||||
|
AND RM.TYPE IN( 'USER','USER-DYNAMIC')
|
||||||
AND RM.ROLEID = R.ID
|
AND RM.ROLEID = R.ID
|
||||||
)
|
)
|
||||||
|
<if test="username != null and username != ''">
|
||||||
|
AND U.USERNAME = #{username}
|
||||||
|
</if>
|
||||||
|
<if test="displayName != null and displayName != ''">
|
||||||
|
AND U.DISPLAYNAME LIKE '%${displayName}%'
|
||||||
|
</if>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
|
||||||
<!-- ROLE_MEMBER Roles Member-->
|
<!-- ROLE_MEMBER Roles Member-->
|
||||||
<select id="groupMemberInRole" parameterType="RoleMember" resultType="Roles">
|
<select id="roleMemberInRole" parameterType="RoleMember" resultType="Roles">
|
||||||
SELECT DISTINCT
|
SELECT DISTINCT
|
||||||
IR.*
|
IR.*
|
||||||
FROM
|
FROM
|
||||||
@ -185,7 +198,7 @@
|
|||||||
1 = 1
|
1 = 1
|
||||||
AND RM.GROUPID = R.ID
|
AND RM.GROUPID = R.ID
|
||||||
AND RM.MEMBERID = IR.ID
|
AND RM.MEMBERID = IR.ID
|
||||||
AND RM.TYPE = 'ROLE'
|
AND RM.TYPE IN( 'USER','USER-DYNAMIC')
|
||||||
<if test="roleId != null and roleId != ''">
|
<if test="roleId != null and roleId != ''">
|
||||||
AND RM.ROLEID = #{roleId}
|
AND RM.ROLEID = #{roleId}
|
||||||
AND R.ID = #{roleId}
|
AND R.ID = #{roleId}
|
||||||
@ -195,5 +208,54 @@
|
|||||||
</if>
|
</if>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<update id="addDynamicRoleMember" parameterType="Roles" >
|
||||||
|
INSERT INTO MXK_ROLE_MEMBER(
|
||||||
|
ID,
|
||||||
|
ROLEID,
|
||||||
|
MEMBERID,
|
||||||
|
TYPE
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
CONCAT_WS('-','UD','${id}',U.ID) ID,
|
||||||
|
'${id}' ROLEID,
|
||||||
|
U.ID MEMBERID,
|
||||||
|
'USER-DYNAMIC' TYPE
|
||||||
|
FROM MXK_USERINFO U
|
||||||
|
WHERE NOT EXISTS(
|
||||||
|
SELECT 1 FROM MXK_ROLE_MEMBER RM
|
||||||
|
WHERE RM.ROLEID=#{id}
|
||||||
|
AND RM.MEMBERID=U.ID
|
||||||
|
AND RM.TYPE='USER-DYNAMIC'
|
||||||
|
)
|
||||||
|
<if test="filters != null and filters != ''">
|
||||||
|
${filters}
|
||||||
|
</if>
|
||||||
|
<if test="orgIdsList != null and orgIdsList != ''">
|
||||||
|
AND U.DEPARTMENTID IN( ${orgIdsList})
|
||||||
|
</if>
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<delete id="deleteDynamicRoleMember" parameterType="Roles" >
|
||||||
|
DELETE FROM MXK_ROLE_MEMBER RM
|
||||||
|
WHERE TYPE = 'USER-DYNAMIC'
|
||||||
|
AND RM.ROLEID=#{id}
|
||||||
|
AND NOT EXISTS(
|
||||||
|
SELECT 1
|
||||||
|
FROM MXK_USERINFO U
|
||||||
|
WHERE 1 = 1
|
||||||
|
AND U.ID=RM.MEMBERID
|
||||||
|
<if test="filters != null and filters != ''">
|
||||||
|
${filters}
|
||||||
|
</if>
|
||||||
|
<if test="orgIdsList != null and orgIdsList != ''">
|
||||||
|
AND U.DEPARTMENTID IN( ${orgIdsList})
|
||||||
|
</if>
|
||||||
|
)
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
<delete id="deleteByRoleId" parameterType="string" >
|
||||||
|
DELETE FROM MXK_ROLE_MEMBER RM
|
||||||
|
WHERE RM.ROLEID=#{value}
|
||||||
|
</delete>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
@ -11,9 +11,17 @@
|
|||||||
</if>
|
</if>
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
|
<select id="queryDynamicRoles" parameterType="Roles" resultType="Roles">
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
`MXK_GROUPS`
|
||||||
|
WHERE
|
||||||
|
DYNAMIC = '1'
|
||||||
|
<include refid="where_statement"/>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="queryPageResults" parameterType="Roles" resultType="Roles">
|
||||||
<select id="queryPageResults" parameterType="Groups" resultType="Groups">
|
|
||||||
SELECT
|
SELECT
|
||||||
*
|
*
|
||||||
FROM
|
FROM
|
||||||
@ -24,7 +32,7 @@
|
|||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
|
||||||
<update id="logisticDelete" parameterType="Groups" >
|
<update id="logisticDelete" parameterType="Roles" >
|
||||||
UPDATE MXK_ROLES SET
|
UPDATE MXK_ROLES SET
|
||||||
STATUS = '2'
|
STATUS = '2'
|
||||||
WHERE 1 = 1
|
WHERE 1 = 1
|
||||||
|
|||||||
@ -24,10 +24,20 @@ import org.maxkey.authz.oauth2.provider.token.TokenStore;
|
|||||||
import org.maxkey.authz.oauth2.provider.token.store.InMemoryTokenStore;
|
import org.maxkey.authz.oauth2.provider.token.store.InMemoryTokenStore;
|
||||||
import org.maxkey.authz.oauth2.provider.token.store.JdbcTokenStore;
|
import org.maxkey.authz.oauth2.provider.token.store.JdbcTokenStore;
|
||||||
import org.maxkey.authz.oauth2.provider.token.store.RedisTokenStore;
|
import org.maxkey.authz.oauth2.provider.token.store.RedisTokenStore;
|
||||||
import org.maxkey.authz.oidc.idtoken.OIDCIdTokenEnhancer;
|
|
||||||
import org.maxkey.constants.ConstantsProperties;
|
import org.maxkey.constants.ConstantsProperties;
|
||||||
import org.maxkey.crypto.password.opt.impl.TimeBasedOtpAuthn;
|
import org.maxkey.crypto.password.opt.impl.TimeBasedOtpAuthn;
|
||||||
|
import org.maxkey.jobs.DynamicGroupsJob;
|
||||||
import org.maxkey.persistence.redis.RedisConnectionFactory;
|
import org.maxkey.persistence.redis.RedisConnectionFactory;
|
||||||
|
import org.maxkey.persistence.service.GroupsService;
|
||||||
|
import org.opensaml.xml.ConfigurationException;
|
||||||
|
import org.quartz.CronScheduleBuilder;
|
||||||
|
import org.quartz.CronTrigger;
|
||||||
|
import org.quartz.JobBuilder;
|
||||||
|
import org.quartz.JobDataMap;
|
||||||
|
import org.quartz.JobDetail;
|
||||||
|
import org.quartz.Scheduler;
|
||||||
|
import org.quartz.SchedulerException;
|
||||||
|
import org.quartz.TriggerBuilder;
|
||||||
import org.maxkey.authn.realm.jdbc.JdbcAuthenticationRealm;
|
import org.maxkey.authn.realm.jdbc.JdbcAuthenticationRealm;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@ -37,6 +47,7 @@ import org.springframework.context.annotation.Bean;
|
|||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.PropertySource;
|
import org.springframework.context.annotation.PropertySource;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ -44,9 +55,8 @@ import org.springframework.security.crypto.password.PasswordEncoder;
|
|||||||
public class MaxKeyMgtConfig implements InitializingBean {
|
public class MaxKeyMgtConfig implements InitializingBean {
|
||||||
private static final Logger _logger = LoggerFactory.getLogger(MaxKeyMgtConfig.class);
|
private static final Logger _logger = LoggerFactory.getLogger(MaxKeyMgtConfig.class);
|
||||||
|
|
||||||
|
|
||||||
|
@Bean(name = "oauth20JdbcClientDetailsService")
|
||||||
@Bean(name = "oauth20JdbcClientDetailsService")
|
|
||||||
public JdbcClientDetailsService JdbcClientDetailsService(
|
public JdbcClientDetailsService JdbcClientDetailsService(
|
||||||
DataSource dataSource,PasswordEncoder passwordReciprocal) {
|
DataSource dataSource,PasswordEncoder passwordReciprocal) {
|
||||||
JdbcClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
|
JdbcClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
|
||||||
@ -111,9 +121,47 @@ public class MaxKeyMgtConfig implements InitializingBean {
|
|||||||
return tfaOptAuthn;
|
return tfaOptAuthn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* schedulerJobsInit.
|
||||||
|
* @return schedulerJobsInit
|
||||||
|
* @throws ConfigurationException
|
||||||
|
* @throws SchedulerException
|
||||||
|
*/
|
||||||
|
@Bean(name = "schedulerJobs")
|
||||||
|
public Scheduler schedulerJobs(
|
||||||
|
SchedulerFactoryBean schedulerFactoryBean,
|
||||||
|
GroupsService groupsService,
|
||||||
|
@Value("${config.job.cron.dynamicgroups}") String cronScheduleDynamicGroups
|
||||||
|
) throws SchedulerException {
|
||||||
|
|
||||||
|
Scheduler scheduler = schedulerFactoryBean.getScheduler();
|
||||||
|
dynamicGroupsJob(scheduler,cronScheduleDynamicGroups,groupsService);
|
||||||
|
|
||||||
|
return scheduler;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void dynamicGroupsJob(Scheduler scheduler ,
|
||||||
|
String cronSchedule,
|
||||||
|
GroupsService groupsService) throws SchedulerException {
|
||||||
|
JobDetail jobDetail =
|
||||||
|
JobBuilder.newJob(DynamicGroupsJob.class)
|
||||||
|
.withIdentity("DynamicGroupsJob", "DynamicGroups")
|
||||||
|
.build();
|
||||||
|
JobDataMap jobDataMap = new JobDataMap();
|
||||||
|
jobDataMap.put("groupsService", groupsService);
|
||||||
|
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronSchedule);
|
||||||
|
CronTrigger cronTrigger =
|
||||||
|
TriggerBuilder.newTrigger()
|
||||||
|
.withIdentity("triggerDynamicGroups", "DynamicGroups")
|
||||||
|
.usingJobData(jobDataMap)
|
||||||
|
.withSchedule(scheduleBuilder)
|
||||||
|
.build();
|
||||||
|
scheduler.scheduleJob(jobDetail,cronTrigger);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet() throws Exception {
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,56 @@
|
|||||||
|
package org.maxkey.jobs;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.maxkey.domain.Groups;
|
||||||
|
import org.maxkey.persistence.service.GroupsService;
|
||||||
|
import org.quartz.Job;
|
||||||
|
import org.quartz.JobExecutionContext;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class DynamicGroupsJob implements Job {
|
||||||
|
final static Logger _logger = LoggerFactory.getLogger(DynamicGroupsJob.class);
|
||||||
|
|
||||||
|
private static GroupsService groupsService = null;
|
||||||
|
|
||||||
|
public static class JOBSTATUS{
|
||||||
|
public static int STOP = 0;
|
||||||
|
public static int RUNNING = 1;
|
||||||
|
public static int FINISHED = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int jobStatus = JOBSTATUS.STOP;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(JobExecutionContext context){
|
||||||
|
if(jobStatus == JOBSTATUS.RUNNING) {
|
||||||
|
_logger.info("DynamicGroupsJob is in running . " );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.debug("DynamicGroupsJob is running ... " );
|
||||||
|
jobStatus = JOBSTATUS.RUNNING;
|
||||||
|
try {
|
||||||
|
if(groupsService == null) {
|
||||||
|
groupsService = (GroupsService) context.getMergedJobDataMap().get("groupsService");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Groups> groupsList = groupsService.queryDynamicGroups(null);
|
||||||
|
for(Groups group : groupsList) {
|
||||||
|
_logger.debug("group " + group);
|
||||||
|
groupsService.refreshDynamicGroups(group);
|
||||||
|
}
|
||||||
|
Thread.sleep(10 *1000);
|
||||||
|
_logger.debug("DynamicGroupsJob is success " );
|
||||||
|
}catch(Exception e) {
|
||||||
|
_logger.error("Exception " ,e);
|
||||||
|
jobStatus = JOBSTATUS.STOP;
|
||||||
|
}
|
||||||
|
jobStatus = JOBSTATUS.FINISHED;
|
||||||
|
_logger.debug("DynamicGroupsJob is finished . " );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
package org.maxkey.jobs;
|
||||||
|
|
||||||
|
public class DynamicRolesJob {
|
||||||
|
|
||||||
|
}
|
||||||
@ -85,6 +85,7 @@ public class GroupsController {
|
|||||||
_logger.debug("-Add :" + group);
|
_logger.debug("-Add :" + group);
|
||||||
|
|
||||||
if (groupsService.insert(group)) {
|
if (groupsService.insert(group)) {
|
||||||
|
groupsService.refreshDynamicGroups(group);
|
||||||
return new Message(WebContext.getI18nValue(ConstantsOperateMessage.INSERT_SUCCESS),MessageType.success);
|
return new Message(WebContext.getI18nValue(ConstantsOperateMessage.INSERT_SUCCESS),MessageType.success);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -122,6 +123,7 @@ public class GroupsController {
|
|||||||
_logger.debug("-update group :" + group);
|
_logger.debug("-update group :" + group);
|
||||||
|
|
||||||
if (groupsService.update(group)) {
|
if (groupsService.update(group)) {
|
||||||
|
groupsService.refreshDynamicGroups(group);
|
||||||
return new Message(WebContext.getI18nValue(ConstantsOperateMessage.UPDATE_SUCCESS),MessageType.success);
|
return new Message(WebContext.getI18nValue(ConstantsOperateMessage.UPDATE_SUCCESS),MessageType.success);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -136,7 +138,7 @@ public class GroupsController {
|
|||||||
public Message delete(@ModelAttribute("group") Groups group) {
|
public Message delete(@ModelAttribute("group") Groups group) {
|
||||||
_logger.debug("-delete group :" + group);
|
_logger.debug("-delete group :" + group);
|
||||||
|
|
||||||
if (groupsService.remove(group.getId())) {
|
if (groupsService.deleteById(group.getId())) {
|
||||||
return new Message(WebContext.getI18nValue(ConstantsOperateMessage.DELETE_SUCCESS),MessageType.success);
|
return new Message(WebContext.getI18nValue(ConstantsOperateMessage.DELETE_SUCCESS),MessageType.success);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -85,6 +85,7 @@ public class RolesController {
|
|||||||
_logger.debug("-Add :" + role);
|
_logger.debug("-Add :" + role);
|
||||||
|
|
||||||
if (rolesService.insert(role)) {
|
if (rolesService.insert(role)) {
|
||||||
|
rolesService.refreshDynamicRoles(role);
|
||||||
return new Message(WebContext.getI18nValue(ConstantsOperateMessage.INSERT_SUCCESS),MessageType.success);
|
return new Message(WebContext.getI18nValue(ConstantsOperateMessage.INSERT_SUCCESS),MessageType.success);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -122,6 +123,7 @@ public class RolesController {
|
|||||||
_logger.debug("-update role :" + role);
|
_logger.debug("-update role :" + role);
|
||||||
|
|
||||||
if (rolesService.update(role)) {
|
if (rolesService.update(role)) {
|
||||||
|
rolesService.refreshDynamicRoles(role);
|
||||||
return new Message(WebContext.getI18nValue(ConstantsOperateMessage.UPDATE_SUCCESS),MessageType.success);
|
return new Message(WebContext.getI18nValue(ConstantsOperateMessage.UPDATE_SUCCESS),MessageType.success);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -136,7 +138,7 @@ public class RolesController {
|
|||||||
public Message delete(@ModelAttribute("role") Roles role) {
|
public Message delete(@ModelAttribute("role") Roles role) {
|
||||||
_logger.debug("-delete role :" + role);
|
_logger.debug("-delete role :" + role);
|
||||||
|
|
||||||
if (rolesService.remove(role.getId())) {
|
if (rolesService.deleteById(role.getId())) {
|
||||||
return new Message(WebContext.getI18nValue(ConstantsOperateMessage.DELETE_SUCCESS),MessageType.success);
|
return new Message(WebContext.getI18nValue(ConstantsOperateMessage.DELETE_SUCCESS),MessageType.success);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -66,4 +66,6 @@ config.oidc.metadata.issuer=https://${config.server.domain}/maxkey
|
|||||||
config.oidc.metadata.authorizationEndpoint=${config.server.name}/maxkey/oauth/v20/authorize
|
config.oidc.metadata.authorizationEndpoint=${config.server.name}/maxkey/oauth/v20/authorize
|
||||||
config.oidc.metadata.tokenEndpoint=${config.server.name}/maxkey/oauth/v20/token
|
config.oidc.metadata.tokenEndpoint=${config.server.name}/maxkey/oauth/v20/token
|
||||||
config.oidc.metadata.userinfoEndpoint=${config.server.name}/maxkey/api/connect/userinfo
|
config.oidc.metadata.userinfoEndpoint=${config.server.name}/maxkey/api/connect/userinfo
|
||||||
#############################################################################
|
#############################################################################
|
||||||
|
#one hour for refresh dynamic groups
|
||||||
|
config.job.cron.dynamicgroups=0 0 0/1 * * ?
|
||||||
@ -420,6 +420,9 @@ group.orgidslist=\u673a\u6784\u5217\u8868
|
|||||||
#role
|
#role
|
||||||
role.id=\u89d2\u8272\u7f16\u7801
|
role.id=\u89d2\u8272\u7f16\u7801
|
||||||
role.name=\u89d2\u8272
|
role.name=\u89d2\u8272
|
||||||
|
role.dynamic=\u52a8\u6001\u7ec4
|
||||||
|
role.filters=\u8fc7\u6ee4\u5668
|
||||||
|
role.orgidslist=\u673a\u6784\u5217\u8868
|
||||||
|
|
||||||
resource.id=\u8d44\u6e90\u7f16\u7801
|
resource.id=\u8d44\u6e90\u7f16\u7801
|
||||||
resource.name=\u8d44\u6e90\u540d\u79f0
|
resource.name=\u8d44\u6e90\u540d\u79f0
|
||||||
|
|||||||
@ -419,6 +419,9 @@ group.orgidslist=orgIdsList
|
|||||||
#role
|
#role
|
||||||
role.id=id
|
role.id=id
|
||||||
role.name=name
|
role.name=name
|
||||||
|
role.dynamic=dynamic
|
||||||
|
role.filters=filters
|
||||||
|
role.orgidslist=orgIdsList
|
||||||
|
|
||||||
resource.id=id
|
resource.id=id
|
||||||
resource.name=name
|
resource.name=name
|
||||||
|
|||||||
@ -421,6 +421,9 @@ group.orgidslist=\u673a\u6784\u5217\u8868
|
|||||||
#role
|
#role
|
||||||
role.id=\u89d2\u8272\u7f16\u7801
|
role.id=\u89d2\u8272\u7f16\u7801
|
||||||
role.name=\u89d2\u8272
|
role.name=\u89d2\u8272
|
||||||
|
role.dynamic=\u52a8\u6001\u7ec4
|
||||||
|
role.filters=\u8fc7\u6ee4\u5668
|
||||||
|
role.orgidslist=\u673a\u6784\u5217\u8868
|
||||||
|
|
||||||
resource.id=\u8d44\u6e90\u7f16\u7801
|
resource.id=\u8d44\u6e90\u7f16\u7801
|
||||||
resource.name=\u8d44\u6e90\u540d\u79f0
|
resource.name=\u8d44\u6e90\u540d\u79f0
|
||||||
|
|||||||
@ -148,7 +148,7 @@ header .header-container .nav-left>li, .header .header-container .nav-right>li {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.page-container .main-content {
|
.page-container .main-content {
|
||||||
padding: calc(50px + 35px) 15px 15px;
|
padding: calc(35px + 35px) 15px 15px;
|
||||||
min-height: calc(100vh - 65px);
|
min-height: calc(100vh - 65px);
|
||||||
background: #e6e8ea;
|
background: #e6e8ea;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -178,13 +178,17 @@ header .header-container .nav-left>li, .header .header-container .nav-right>li {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.breadcrumb-wrapper {
|
.breadcrumb-wrapper {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
-webkit-box-align: center;
|
-webkit-box-align: center;
|
||||||
-ms-flex-align: center;
|
-ms-flex-align: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content-wrapper {
|
||||||
|
padding-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
.breadcrumb-wrapper .breadcrumb li {
|
.breadcrumb-wrapper .breadcrumb li {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
|||||||
@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
|
<div class="content-wrapper row">
|
||||||
<div class="col-12 grid-margin">
|
<div class="col-12 grid-margin">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -113,6 +113,7 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<footer class="content-footer">
|
<footer class="content-footer">
|
||||||
|
|||||||
@ -111,6 +111,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
|
<div class="content-wrapper row">
|
||||||
<div class="col-12 grid-margin">
|
<div class="col-12 grid-margin">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -209,6 +210,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<footer class="content-footer">
|
<footer class="content-footer">
|
||||||
<#include "../layout/footer.ftl"/>
|
<#include "../layout/footer.ftl"/>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@ -57,6 +57,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
|
<div class="content-wrapper row">
|
||||||
<div class="col-12 grid-margin">
|
<div class="col-12 grid-margin">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header border-bottom">
|
<div class="card-header border-bottom">
|
||||||
@ -241,6 +242,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<footer class="content-footer">
|
<footer class="content-footer">
|
||||||
<#include "../../layout/footer.ftl"/>
|
<#include "../../layout/footer.ftl"/>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@ -58,6 +58,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
|
<div class="content-wrapper row">
|
||||||
<div class="col-12 grid-margin">
|
<div class="col-12 grid-margin">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -140,7 +141,7 @@
|
|||||||
<footer class="content-footer">
|
<footer class="content-footer">
|
||||||
<#include "../layout/footer.ftl"/>
|
<#include "../layout/footer.ftl"/>
|
||||||
</footer>
|
</footer>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -3,13 +3,13 @@
|
|||||||
<head>
|
<head>
|
||||||
<#include "../layout/header.ftl"/>
|
<#include "../layout/header.ftl"/>
|
||||||
<#include "../layout/common.cssjs.ftl"/>
|
<#include "../layout/common.cssjs.ftl"/>
|
||||||
|
<script type="text/javascript">
|
||||||
|
function dynamicFormatter(value, row, index){
|
||||||
|
return value=='0'? '<@locale code="common.text.no" />':'<@locale code="common.text.yes" />';
|
||||||
|
};
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<script type="text/javascript">
|
|
||||||
function dynamicFormatter(value, row, index){
|
|
||||||
return value=='0'? '<@locale code="common.text.no" />':'<@locale code="common.text.yes" />';
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
<body>
|
<body>
|
||||||
<div class="app header-default side-nav-dark">
|
<div class="app header-default side-nav-dark">
|
||||||
<div class="layout">
|
<div class="layout">
|
||||||
@ -37,6 +37,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
|
<div class="content-wrapper row">
|
||||||
<div class="col-12 grid-margin">
|
<div class="col-12 grid-margin">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -113,6 +114,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<footer class="content-footer">
|
<footer class="content-footer">
|
||||||
<#include "../layout/footer.ftl"/>
|
<#include "../layout/footer.ftl"/>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@ -54,7 +54,7 @@
|
|||||||
<td width="120px"><@locale code="userinfo.username"/>:</td>
|
<td width="120px"><@locale code="userinfo.username"/>:</td>
|
||||||
<td width="374px">
|
<td width="374px">
|
||||||
<form id="basic_search_form">
|
<form id="basic_search_form">
|
||||||
<input class="form-control" type="text" name="name" style ="width:150px;float:left;">
|
<input class="form-control" type="text" name="username" style ="width:150px;float:left;">
|
||||||
<input class="button btn btn-primary mr-3" id="searchBtn" type="button" size="50" value="<@locale code="button.text.search"/>">
|
<input class="button btn btn-primary mr-3" id="searchBtn" type="button" size="50" value="<@locale code="button.text.search"/>">
|
||||||
</form>
|
</form>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@ -57,6 +57,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
|
<div class="content-wrapper row">
|
||||||
<div class="col-12 grid-margin">
|
<div class="col-12 grid-margin">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -151,7 +152,7 @@
|
|||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -11,28 +11,22 @@
|
|||||||
<@locale code="global.application"/>
|
<@locale code="global.application"/>
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="nav-right">
|
<ul class="nav-right">
|
||||||
<li style="font-size: 18px; margin-top: 10px;">
|
<li style="font-size: 16px; margin-top: 10px;">
|
||||||
<@locale code="global.text.welcome"/>:<b>
|
<@locale code="global.text.welcome"/>:<b>
|
||||||
<#if Session["current_user"]?exists>
|
<#if Session["current_user"]?exists>
|
||||||
${Session["current_user"].displayName}
|
${Session["current_user"].displayName}
|
||||||
|
(${Session["current_user"].username})
|
||||||
</#if>
|
</#if>
|
||||||
(
|
</b>
|
||||||
<#if Session["current_user"]?exists>
|
|
||||||
${Session["current_user"].username}
|
|
||||||
</#if>
|
|
||||||
) </b>
|
|
||||||
</li>
|
</li>
|
||||||
<li class="scale-left">
|
<li class="scale-left" style="margin-top: 5px;">
|
||||||
<a class="sidenav-fold-toggler" href="javascript:void(0);">
|
<a class="sidenav-fold-toggler" href="javascript:void(0);" >
|
||||||
<img src="<@base/>/static/images/menu-left.png" alt="" style="width: 30px; height: 40px; padding-top: 10px;">
|
<i class="fa fa-bars fa-2x" aria-hidden="true" style="border:0px"></i>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="scale-left">
|
<li class="scale-left" style="font-size: 18px; margin-top: 5px;">
|
||||||
|
|
||||||
</li>
|
|
||||||
<li class="scale-left">
|
|
||||||
<a href="<@base/>/logout?reLoginUrl=login">
|
<a href="<@base/>/logout?reLoginUrl=login">
|
||||||
<IMG SRC="<@base/>/static/images/exit4.png" alt="Exit" style="width: 40px; height: 45px; padding-top: 8px;">
|
<i class="fa fa-sign-out fa-2x" aria-hidden="true" style="border:0px;color:#e22a6f"></i>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
$(function(){
|
$(function(){
|
||||||
<#if true==isCaptcha>
|
<#if true==isCaptcha>
|
||||||
$('#j_captchaimg').click(function () {//
|
$('#j_captchaimg').click(function () {//
|
||||||
$(this).attr("src", "<@base />/captcha");
|
$(this).attr("src", "<@base />/captcha?"+(new Date()).getTime());
|
||||||
});
|
});
|
||||||
</#if>
|
</#if>
|
||||||
});
|
});
|
||||||
|
|||||||
@ -37,7 +37,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
|
<div class="content-wrapper row">
|
||||||
<div class="col-12 grid-margin">
|
<div class="col-12 grid-margin">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -121,6 +121,7 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<footer class="content-footer">
|
<footer class="content-footer">
|
||||||
|
|||||||
@ -37,7 +37,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
|
<div class="content-wrapper row">
|
||||||
<div class="col-12 grid-margin">
|
<div class="col-12 grid-margin">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -130,6 +130,7 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<footer class="content-footer">
|
<footer class="content-footer">
|
||||||
|
|||||||
@ -37,7 +37,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
|
<div class="content-wrapper row">
|
||||||
<div class="col-12 grid-margin">
|
<div class="col-12 grid-margin">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -124,6 +124,7 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<footer class="content-footer">
|
<footer class="content-footer">
|
||||||
|
|||||||
@ -41,10 +41,10 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row">
|
<div class="row" style="height:115px; padding-top: 10px;">
|
||||||
<div class="col-lg-3 col-md-6 col-xs-12">
|
<div class="col-lg-3 col-md-6 col-xs-12">
|
||||||
<div class="info-box bg-primary">
|
<div class="card text-white bg-primary">
|
||||||
<div class="icon-box">
|
<div class="card-body card-body pb-0 d-flex justify-content-between align-items-start">
|
||||||
<i class="lni-home"></i>
|
<i class="lni-home"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-box-content">
|
<div class="info-box-content">
|
||||||
@ -54,8 +54,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-3 col-md-6 col-xs-12">
|
<div class="col-lg-3 col-md-6 col-xs-12">
|
||||||
<div class="info-box bg-success">
|
<div class="card text-white bg-info">
|
||||||
<div class="icon-box">
|
<div class="card-body card-body pb-0 d-flex justify-content-between align-items-start">
|
||||||
<i class="lni-tag"></i>
|
<i class="lni-tag"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-box-content">
|
<div class="info-box-content">
|
||||||
@ -65,8 +65,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-3 col-md-6 col-xs-12">
|
<div class="col-lg-3 col-md-6 col-xs-12">
|
||||||
<div class="info-box bg-info">
|
<div class="card text-white bg-warning">
|
||||||
<div class="icon-box">
|
<div class="card-body card-body pb-0 d-flex justify-content-between align-items-start">
|
||||||
<i class="lni-cart"></i>
|
<i class="lni-cart"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-box-content">
|
<div class="info-box-content">
|
||||||
@ -76,8 +76,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-3 col-md-6 col-xs-12">
|
<div class="col-lg-3 col-md-6 col-xs-12">
|
||||||
<div class="info-box bg-purple">
|
<div class="card text-white bg-danger">
|
||||||
<div class="icon-box">
|
<div class="card-body card-body pb-0 d-flex justify-content-between align-items-start">
|
||||||
<i class="lni-wallet"></i>
|
<i class="lni-wallet"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-box-content">
|
<div class="info-box-content">
|
||||||
|
|||||||
@ -163,7 +163,7 @@ $(function () {
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
|
<div class="content-wrapper row">
|
||||||
<div class="col-12 grid-margin">
|
<div class="col-12 grid-margin">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -249,10 +249,11 @@ $(function () {
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<footer class="content-footer">
|
<footer class="content-footer">
|
||||||
<#include "../layout/footer.ftl"/>
|
<#include "../layout/footer.ftl"/>
|
||||||
</footer>
|
</footer>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -232,6 +232,7 @@ $('#datagrid').on('click-row.bs.table', function (row, element, field) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
|
<div class="content-wrapper row">
|
||||||
<div class="col-12 grid-margin">
|
<div class="col-12 grid-margin">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -314,6 +315,7 @@ $('#datagrid').on('click-row.bs.table', function (row, element, field) {
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<footer class="content-footer">
|
<footer class="content-footer">
|
||||||
<#include "../layout/footer.ftl"/>
|
<#include "../layout/footer.ftl"/>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@ -163,6 +163,7 @@ $(function () {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
|
<div class="content-wrapper row">
|
||||||
<div class="col-12 grid-margin">
|
<div class="col-12 grid-margin">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -254,12 +255,12 @@ $(function () {
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<footer class="content-footer">
|
<footer class="content-footer">
|
||||||
<#include "../layout/footer.ftl"/>
|
<#include "../layout/footer.ftl"/>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,155 @@
|
|||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<script type="text/javascript">
|
||||||
|
function onClick (event, treeId, treeNode) {
|
||||||
|
var zTree = $.fn.zTree.getZTreeObj("orgsTree");
|
||||||
|
nodes = zTree.getCheckedNodes(true);
|
||||||
|
var orgsName = "";
|
||||||
|
var orgsId = "";
|
||||||
|
for (var i=0, l=nodes.length; i<l; i++) {
|
||||||
|
orgsName += nodes[i].name + ",";
|
||||||
|
orgsId += nodes[i].id + ",";
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#orgIdsListName").val(orgsName);
|
||||||
|
$("#orgIdsList").val(orgsId);
|
||||||
|
}
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
|
||||||
|
var treeSettings={
|
||||||
|
element : "orgsTree",
|
||||||
|
rootId : "1",
|
||||||
|
checkbox : true,
|
||||||
|
onClick : onClick,
|
||||||
|
onDblClick : null,
|
||||||
|
url : "<@base/>/orgs/tree"
|
||||||
|
};
|
||||||
|
|
||||||
|
function singlePath(newNode) {
|
||||||
|
if (newNode === curExpandNode) return;
|
||||||
|
if (curExpandNode && curExpandNode.open==true) {
|
||||||
|
var zTree = $.fn.zTree.getZTreeObj(treeSettings.element);
|
||||||
|
if (newNode.parentTId === curExpandNode.parentTId) {
|
||||||
|
zTree.expandNode(curExpandNode, false);
|
||||||
|
} else {
|
||||||
|
var newParents = [];
|
||||||
|
while (newNode) {
|
||||||
|
newNode = newNode.getParentNode();
|
||||||
|
if (newNode === curExpandNode) {
|
||||||
|
newParents = null;
|
||||||
|
break;
|
||||||
|
} else if (newNode) {
|
||||||
|
newParents.push(newNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (newParents!=null) {
|
||||||
|
var oldNode = curExpandNode;
|
||||||
|
var oldParents = [];
|
||||||
|
while (oldNode) {
|
||||||
|
oldNode = oldNode.getParentNode();
|
||||||
|
if (oldNode) {
|
||||||
|
oldParents.push(oldNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (newParents.length>0) {
|
||||||
|
for (var i = Math.min(newParents.length, oldParents.length)-1; i>=0; i--) {
|
||||||
|
if (newParents[i] !== oldParents[i]) {
|
||||||
|
zTree.expandNode(oldParents[i], false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
zTree.expandNode(oldParents[oldParents.length-1], false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
curExpandNode = newNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function beforeExpand(treeId, treeNode) {
|
||||||
|
var pNode = curExpandNode ? curExpandNode.getParentNode():null;
|
||||||
|
var treeNodeP = treeNode.parentTId ? treeNode.getParentNode():null;
|
||||||
|
var zTree = $.fn.zTree.getZTreeObj(""+treeSettings.element);
|
||||||
|
for(var i=0, l=!treeNodeP ? 0:treeNodeP.children.length; i<l; i++ ) {
|
||||||
|
if (treeNode !== treeNodeP.children[i]) {
|
||||||
|
zTree.expandNode(treeNodeP.children[i], false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (pNode) {
|
||||||
|
if (pNode === treeNode) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pNode = pNode.getParentNode();
|
||||||
|
}
|
||||||
|
if (!pNode) {
|
||||||
|
singlePath(treeNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
$.fn.zTree.init(
|
||||||
|
$("#"+treeSettings.element), //element
|
||||||
|
{//json object
|
||||||
|
check : {
|
||||||
|
enable : treeSettings.checkbox
|
||||||
|
},
|
||||||
|
async : {
|
||||||
|
enable : true,
|
||||||
|
url : treeSettings.url,
|
||||||
|
autoParam : ["id", "name=n", "level=lv"],
|
||||||
|
otherParam : {"otherParam":"zTreeAsyncTest",id:treeSettings.rootId},
|
||||||
|
dataFilter : function (treeId, parentNode, childNodes) {
|
||||||
|
if (!childNodes) return null;
|
||||||
|
for (var i=0, l=childNodes.length; i<l; i++) {
|
||||||
|
childNodes[i].name = childNodes[i].name.replace(/\.n/g, '.');
|
||||||
|
}
|
||||||
|
return childNodes;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data : {
|
||||||
|
simpleData : {
|
||||||
|
enable : true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
callback: {
|
||||||
|
onClick : treeSettings.onClick,
|
||||||
|
onDblClick : treeSettings.onDblClick,
|
||||||
|
beforeAsync : function(treeId, treeNode){
|
||||||
|
$.loading();
|
||||||
|
},
|
||||||
|
onAsyncSuccess : function(event, treeId, treeNode, msg){
|
||||||
|
$.unloading();
|
||||||
|
},
|
||||||
|
//beforeExpand : beforeExpand,
|
||||||
|
onExpand : function onExpand(event, treeId, treeNode) {
|
||||||
|
curExpandNode = treeNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);//end tree
|
||||||
|
|
||||||
|
});
|
||||||
|
function onBodyDown(event) {
|
||||||
|
if (!(event.target.id == "menuBtn" || event.target.id == "orgIdsListName" || event.target.id == "orgContent" || $(event.target).parents("#orgContent").length>0)) {
|
||||||
|
$("#orgContent").fadeOut("fast");
|
||||||
|
$("body").unbind("mousedown", onBodyDown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showOrgsTree() {
|
||||||
|
var treeObj = $("#orgIdsListName");
|
||||||
|
var treeOffset = $("#orgIdsListName").offset();
|
||||||
|
$("#orgContent").css({left:treeOffset.left + "px", top:treeOffset.top + treeObj.outerHeight() + "px"}).slideDown("fast");
|
||||||
|
|
||||||
|
$("body").bind("mousedown", onBodyDown);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<form id="actionForm" method="post" type="label" autoclose="true" action="<@base/>/roles/add" class="needs-validation" novalidate>
|
<form id="actionForm" method="post" type="label" autoclose="true" action="<@base/>/roles/add" class="needs-validation" novalidate>
|
||||||
@ -26,10 +175,32 @@
|
|||||||
<input type="text" id="name" name="name" class="form-control" title="" value="" required="" />
|
<input type="text" id="name" name="name" class="form-control" title="" value="" required="" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><@locale code="role.dynamic" />:</th>
|
||||||
|
<td nowrap>
|
||||||
|
<select id="dynamic" name="dynamic" class="form-control">
|
||||||
|
<option value="0" selected ><@locale code="common.text.no" /></option>
|
||||||
|
<option value="1" ><@locale code="common.text.yes" /></option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><@locale code="role.orgidslist" />:</th>
|
||||||
|
<td nowrap>
|
||||||
|
<input type="text" id="orgIdsListName" name="orgIdsListName" readonly class="form-control" title="" value="" onclick="showOrgsTree();"/>
|
||||||
|
<input type="hidden" id="orgIdsList" name="orgIdsList" readonly class="form-control" title="" value="" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><@locale code="role.filters" />:</th>
|
||||||
|
<td nowrap>
|
||||||
|
<textarea id="filters" name="filters" class="form-control" rows="7" cols="20"></textarea>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th><@locale code="common.text.description" />:</th>
|
<th><@locale code="common.text.description" />:</th>
|
||||||
<td nowrap>
|
<td nowrap>
|
||||||
<input type="text" id="description" name="description" class="form-control" title="" value="" />
|
<textarea id="description" name="description" class="form-control" rows="6" cols="20"></textarea>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
@ -44,5 +215,8 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</form>
|
</form>
|
||||||
|
<div id="orgContent" class="menuContent" style="display:none; position: absolute;">
|
||||||
|
<ul id="orgsTree" class="ztree" style="margin-top:0; width:180px; height: 300px;"></ul>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@ -9,6 +9,169 @@
|
|||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<script type="text/javascript">
|
||||||
|
function onClick (event, treeId, treeNode) {
|
||||||
|
var zTree = $.fn.zTree.getZTreeObj("orgsTree");
|
||||||
|
nodes = zTree.getCheckedNodes(true);
|
||||||
|
var orgsName = "";
|
||||||
|
var orgsId = "";
|
||||||
|
for (var i=0; i<nodes.length; i++) {
|
||||||
|
orgsName += nodes[i].name + ",";
|
||||||
|
orgsId += nodes[i].id + ",";
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#orgIdsListName").val(orgsName);
|
||||||
|
$("#orgIdsList").val(orgsId);
|
||||||
|
}
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
|
||||||
|
var treeSettings={
|
||||||
|
element : "orgsTree",
|
||||||
|
rootId : "1",
|
||||||
|
checkbox : true,
|
||||||
|
onClick : onClick,
|
||||||
|
onDblClick : null,
|
||||||
|
url : "<@base/>/orgs/tree"
|
||||||
|
};
|
||||||
|
|
||||||
|
function singlePath(newNode) {
|
||||||
|
if (newNode === curExpandNode) return;
|
||||||
|
if (curExpandNode && curExpandNode.open==true) {
|
||||||
|
var zTree = $.fn.zTree.getZTreeObj(treeSettings.element);
|
||||||
|
if (newNode.parentTId === curExpandNode.parentTId) {
|
||||||
|
zTree.expandNode(curExpandNode, false);
|
||||||
|
} else {
|
||||||
|
var newParents = [];
|
||||||
|
while (newNode) {
|
||||||
|
newNode = newNode.getParentNode();
|
||||||
|
if (newNode === curExpandNode) {
|
||||||
|
newParents = null;
|
||||||
|
break;
|
||||||
|
} else if (newNode) {
|
||||||
|
newParents.push(newNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (newParents!=null) {
|
||||||
|
var oldNode = curExpandNode;
|
||||||
|
var oldParents = [];
|
||||||
|
while (oldNode) {
|
||||||
|
oldNode = oldNode.getParentNode();
|
||||||
|
if (oldNode) {
|
||||||
|
oldParents.push(oldNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (newParents.length>0) {
|
||||||
|
for (var i = Math.min(newParents.length, oldParents.length)-1; i>=0; i--) {
|
||||||
|
if (newParents[i] !== oldParents[i]) {
|
||||||
|
zTree.expandNode(oldParents[i], false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
zTree.expandNode(oldParents[oldParents.length-1], false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
curExpandNode = newNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function beforeExpand(treeId, treeNode) {
|
||||||
|
var pNode = curExpandNode ? curExpandNode.getParentNode():null;
|
||||||
|
var treeNodeP = treeNode.parentTId ? treeNode.getParentNode():null;
|
||||||
|
var zTree = $.fn.zTree.getZTreeObj(""+treeSettings.element);
|
||||||
|
for(var i=0, l=!treeNodeP ? 0:treeNodeP.children.length; i<l; i++ ) {
|
||||||
|
if (treeNode !== treeNodeP.children[i]) {
|
||||||
|
zTree.expandNode(treeNodeP.children[i], false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (pNode) {
|
||||||
|
if (pNode === treeNode) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pNode = pNode.getParentNode();
|
||||||
|
}
|
||||||
|
if (!pNode) {
|
||||||
|
singlePath(treeNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
function onLoadSuccessed(){
|
||||||
|
var zTree = $.fn.zTree.getZTreeObj("orgsTree");
|
||||||
|
var orgsIdValues = $("#orgIdsList").val().split(",") ;
|
||||||
|
var orgsName="";
|
||||||
|
for (var i=0; i<orgsIdValues.length; i++) {
|
||||||
|
var node = zTree.getNodeByParam("id",orgsIdValues[i] );
|
||||||
|
if(node != null){
|
||||||
|
zTree.checkNode(node, true, false);//将指定ID的节点选中
|
||||||
|
orgsName += node.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$("#orgIdsListName").val(orgsName);
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.zTree.init(
|
||||||
|
$("#"+treeSettings.element), //element
|
||||||
|
{//json object
|
||||||
|
check : {
|
||||||
|
enable : treeSettings.checkbox
|
||||||
|
},
|
||||||
|
async : {
|
||||||
|
enable : true,
|
||||||
|
url : treeSettings.url,
|
||||||
|
autoParam : ["id", "name=n", "level=lv"],
|
||||||
|
otherParam : {"otherParam":"zTreeAsyncTest",id:treeSettings.rootId},
|
||||||
|
dataFilter : function (treeId, parentNode, childNodes) {
|
||||||
|
if (!childNodes) return null;
|
||||||
|
for (var i=0, l=childNodes.length; i<l; i++) {
|
||||||
|
childNodes[i].name = childNodes[i].name.replace(/\.n/g, '.');
|
||||||
|
}
|
||||||
|
return childNodes;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data : {
|
||||||
|
simpleData : {
|
||||||
|
enable : true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
callback: {
|
||||||
|
onClick : treeSettings.onClick,
|
||||||
|
onDblClick : treeSettings.onDblClick,
|
||||||
|
beforeAsync : function(treeId, treeNode){
|
||||||
|
$.loading();
|
||||||
|
},
|
||||||
|
onAsyncSuccess : function(event, treeId, treeNode, msg){
|
||||||
|
$.unloading();
|
||||||
|
onLoadSuccessed();
|
||||||
|
},
|
||||||
|
//beforeExpand : beforeExpand,
|
||||||
|
onExpand : function onExpand(event, treeId, treeNode) {
|
||||||
|
curExpandNode = treeNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);//end tree
|
||||||
|
|
||||||
|
});
|
||||||
|
function onBodyDown(event) {
|
||||||
|
if (!(event.target.id == "menuBtn" || event.target.id == "orgIdsListName" || event.target.id == "orgContent" || $(event.target).parents("#orgContent").length>0)) {
|
||||||
|
$("#orgContent").fadeOut("fast");
|
||||||
|
$("body").unbind("mousedown", onBodyDown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showOrgsTree() {
|
||||||
|
var treeObj = $("#orgIdsListName");
|
||||||
|
var treeOffset = $("#orgIdsListName").offset();
|
||||||
|
$("#orgContent").css({left:treeOffset.left + "px", top:treeOffset.top + treeObj.outerHeight() + "px"}).slideDown("fast");
|
||||||
|
|
||||||
|
$("body").bind("mousedown", onBodyDown);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<form id="actionForm" method="post" type="label" autoclose="true" action="<@base/>/roles/update" class="needs-validation" novalidate>
|
<form id="actionForm" method="post" type="label" autoclose="true" action="<@base/>/roles/update" class="needs-validation" novalidate>
|
||||||
@ -26,10 +189,32 @@
|
|||||||
<input type="text" id="name" name="name" class="form-control" title="" value="${model.name!}" required="" />
|
<input type="text" id="name" name="name" class="form-control" title="" value="${model.name!}" required="" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><@locale code="role.dynamic" />:</th>
|
||||||
|
<td nowrap>
|
||||||
|
<select id="dynamic" name="dynamic" class="form-control">
|
||||||
|
<option value="0" <#if '0'==model.dynamic>selected</#if> ><@locale code="common.text.no" /></option>
|
||||||
|
<option value="1" <#if '1'==model.dynamic>selected</#if> ><@locale code="common.text.yes" /></option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><@locale code="role.orgidslist" />:</th>
|
||||||
|
<td nowrap>
|
||||||
|
<input type="text" id="orgIdsListName" name="orgIdsListName" readonly class="form-control" title="" value="" onclick="showOrgsTree();"/>
|
||||||
|
<input type="hidden" id="orgIdsList" name="orgIdsList" readonly class="form-control" title="" value="${model.orgIdsList!}" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><@locale code="role.filters" />:</th>
|
||||||
|
<td nowrap>
|
||||||
|
<textarea id="filters" name="filters" class="form-control" rows="7" cols="20">${model.filters!}</textarea>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th><@locale code="common.text.description" />:</th>
|
<th><@locale code="common.text.description" />:</th>
|
||||||
<td nowrap>
|
<td nowrap>
|
||||||
<input type="text" id="description" name="description" class="form-control" title="" value="${model.description!}" />
|
<textarea id="description" name="description" class="form-control" rows="6" cols="20">${model.description!}</textarea>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@ -43,5 +228,8 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</form>
|
</form>
|
||||||
|
<div id="orgContent" class="menuContent" style="display:none; position: absolute;">
|
||||||
|
<ul id="orgsTree" class="ztree" style="margin-top:0; width:180px; height: 300px;"></ul>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@ -3,7 +3,11 @@
|
|||||||
<head>
|
<head>
|
||||||
<#include "../layout/header.ftl"/>
|
<#include "../layout/header.ftl"/>
|
||||||
<#include "../layout/common.cssjs.ftl"/>
|
<#include "../layout/common.cssjs.ftl"/>
|
||||||
|
<script type="text/javascript">
|
||||||
|
function dynamicFormatter(value, row, index){
|
||||||
|
return value=='0'? '<@locale code="common.text.no" />':'<@locale code="common.text.yes" />';
|
||||||
|
};
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="app header-default side-nav-dark">
|
<div class="app header-default side-nav-dark">
|
||||||
@ -32,6 +36,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
|
<div class="content-wrapper row">
|
||||||
<div class="col-12 grid-margin">
|
<div class="col-12 grid-margin">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -52,13 +57,13 @@
|
|||||||
<input class="button btn btn-success mr-3" id="addBtn" type="button" value="<@locale code="button.text.add"/>"
|
<input class="button btn btn-success mr-3" id="addBtn" type="button" value="<@locale code="button.text.add"/>"
|
||||||
wurl="<@base/>/roles/forwardAdd"
|
wurl="<@base/>/roles/forwardAdd"
|
||||||
wwidth="500"
|
wwidth="500"
|
||||||
wheight="200"
|
wheight="600"
|
||||||
target="window">
|
target="window">
|
||||||
|
|
||||||
<input class="button btn btn-info mr-3 " id="modifyBtn" type="button" value="<@locale code="button.text.edit"/>"
|
<input class="button btn btn-info mr-3 " id="modifyBtn" type="button" value="<@locale code="button.text.edit"/>"
|
||||||
wurl="<@base/>/roles/forwardUpdate"
|
wurl="<@base/>/roles/forwardUpdate"
|
||||||
wwidth="500"
|
wwidth="500"
|
||||||
wheight="200"
|
wheight="600"
|
||||||
target="window">
|
target="window">
|
||||||
|
|
||||||
<input class="button btn btn-danger mr-3 " id="deleteBtn" type="button" value="<@locale code="button.text.delete"/>"
|
<input class="button btn btn-danger mr-3 " id="deleteBtn" type="button" value="<@locale code="button.text.delete"/>"
|
||||||
@ -94,11 +99,12 @@
|
|||||||
<th data-checkbox="true"></th>
|
<th data-checkbox="true"></th>
|
||||||
<th data-sortable="true" data-field="id" data-visible="false">Id</th>
|
<th data-sortable="true" data-field="id" data-visible="false">Id</th>
|
||||||
<th data-field="name"><@locale code="role.name"/></th>
|
<th data-field="name"><@locale code="role.name"/></th>
|
||||||
|
<th data-field="dynamic" data-formatter="dynamicFormatter"><@locale code="group.dynamic"/></th>
|
||||||
<th data-field="description"><@locale code="common.text.description"/></th>
|
<th data-field="description"><@locale code="common.text.description"/></th>
|
||||||
<th data-field="createdBy"><@locale code="common.text.createdby"/></th>
|
<th data-field="createdBy" data-visible="false"><@locale code="common.text.createdby"/></th>
|
||||||
<th data-field="createdDate"><@locale code="common.text.createddate"/></th>
|
<th data-field="createdDate" data-visible="false"><@locale code="common.text.createddate"/></th>
|
||||||
<th data-field="modifiedBy"><@locale code="common.text.modifiedby"/></th>
|
<th data-field="modifiedBy" data-visible="false"><@locale code="common.text.modifiedby"/></th>
|
||||||
<th data-field="modifiedDate"><@locale code="common.text.modifieddate"/></th>
|
<th data-field="modifiedDate" data-visible="false"><@locale code="common.text.modifieddate"/></th>
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -107,10 +113,10 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<footer class="content-footer">
|
<footer class="content-footer">
|
||||||
<#include "../layout/footer.ftl"/>
|
<#include "../layout/footer.ftl"/>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -54,7 +54,7 @@
|
|||||||
<td width="120px"><@locale code="userinfo.username"/>:</td>
|
<td width="120px"><@locale code="userinfo.username"/>:</td>
|
||||||
<td width="374px">
|
<td width="374px">
|
||||||
<form id="basic_search_form">
|
<form id="basic_search_form">
|
||||||
<input class="form-control" type="text" name="name" style ="width:150px;float:left;">
|
<input class="form-control" type="text" name="username" style ="width:150px;float:left;">
|
||||||
<input class="button btn btn-primary mr-3" id="searchBtn" type="button" size="50" value="<@locale code="button.text.search"/>">
|
<input class="button btn btn-primary mr-3" id="searchBtn" type="button" size="50" value="<@locale code="button.text.search"/>">
|
||||||
</form>
|
</form>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@ -57,6 +57,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
|
<div class="content-wrapper row">
|
||||||
<div class="col-12 grid-margin">
|
<div class="col-12 grid-margin">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -146,10 +147,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<footer class="content-footer">
|
<footer class="content-footer">
|
||||||
<#include "../layout/footer.ftl"/>
|
<#include "../layout/footer.ftl"/>
|
||||||
</footer>
|
</footer>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -177,7 +177,7 @@ $(function () {
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
|
<div class="content-wrapper row">
|
||||||
<div class="col-12 grid-margin">
|
<div class="col-12 grid-margin">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -292,6 +292,7 @@ $(function () {
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<footer class="content-footer">
|
<footer class="content-footer">
|
||||||
<#include "../layout/footer.ftl"/>
|
<#include "../layout/footer.ftl"/>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@ -131,7 +131,7 @@
|
|||||||
<#--on captcha image click ,new a captcha code-->
|
<#--on captcha image click ,new a captcha code-->
|
||||||
<#if true==isCaptcha>
|
<#if true==isCaptcha>
|
||||||
$('#j_captchaimg').click(function () {//
|
$('#j_captchaimg').click(function () {//
|
||||||
$(this).attr("src", "<@base />/captcha"+(new Date()).getTime());
|
$(this).attr("src", "<@base />/captcha?"+(new Date()).getTime());
|
||||||
});
|
});
|
||||||
</#if>
|
</#if>
|
||||||
|
|
||||||
|
|||||||
949
sql/maxkey_v2.4.0.RC2.sql
Normal file
949
sql/maxkey_v2.4.0.RC2.sql
Normal file
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user