CongressService & MomentaryService

This commit is contained in:
MaxKey
2022-04-17 07:04:28 +08:00
parent 5e4923d6b4
commit d9af91de4a
82 changed files with 732 additions and 3665 deletions

View File

@@ -30,6 +30,7 @@ public class LoginCredential implements Authentication {
*
*/
private static final long serialVersionUID = 3125709257481600320L;
String congress;
String username;
String password;
String sessionId;
@@ -64,7 +65,15 @@ public class LoginCredential implements Authentication {
this.authType = authType;
}
@Override
public String getCongress() {
return congress;
}
public void setCongress(String congress) {
this.congress = congress;
}
@Override
public String getName() {
return "Login Credential";
}

View File

@@ -17,6 +17,7 @@
package org.maxkey.authn.jwt;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@@ -24,7 +25,10 @@ import org.maxkey.authn.SigninPrincipal;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
public class AuthJwt {
public class AuthJwt implements Serializable {
private static final long serialVersionUID = -914373258878811144L;
private String ticket;
private String token;
private String type = "Bearer";

View File

@@ -24,6 +24,7 @@ import org.maxkey.authn.SigninPrincipal;
import org.maxkey.configuration.AuthJwkConfig;
import org.maxkey.crypto.jwt.HMAC512Service;
import org.maxkey.entity.UserInfo;
import org.maxkey.web.WebContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
@@ -41,6 +42,8 @@ public class AuthJwtService {
HMAC512Service hmac512Service;
AuthJwkConfig authJwkConfig;
CongressService congressService;
public AuthJwtService(AuthJwkConfig authJwkConfig) throws JOSEException {
this.authJwkConfig = authJwkConfig;
@@ -48,6 +51,17 @@ public class AuthJwtService {
this.hmac512Service = new HMAC512Service(authJwkConfig.getSecret());
}
public AuthJwtService(AuthJwkConfig authJwkConfig,CongressService congressService) throws JOSEException {
this.authJwkConfig = authJwkConfig;
this.congressService = congressService;
this.hmac512Service = new HMAC512Service(authJwkConfig.getSecret());
}
public AuthJwt generateAuthJwt(Authentication authentication) {
return new AuthJwt(generateToken(authentication), authentication);
}
public String generateToken(Authentication authentication) {
String token = "";
SigninPrincipal principal = ((SigninPrincipal)authentication.getPrincipal());
@@ -95,4 +109,20 @@ public class AuthJwtService {
return claims.getJWTID();
}
public String createCongress(Authentication authentication) {
String congress = WebContext.genId();
congressService.store(
congress,
new AuthJwt(
generateToken(authentication),
authentication)
);
return congress;
}
public AuthJwt consumeCongress(String congress) {
AuthJwt authJwt = congressService.consume(congress);
return authJwt;
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
*
* Licensed 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.
*/
package org.maxkey.authn.jwt;
public interface CongressService {
public void store(String congress, AuthJwt authJwt);
public AuthJwt consume(String congress);
public AuthJwt remove(String congress);
public AuthJwt get(String congress);
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
*
* Licensed 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.
*/
package org.maxkey.authn.jwt;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
public class InMemoryCongressService implements CongressService{
private static final Logger _logger = LoggerFactory.getLogger(InMemoryCongressService.class);
protected static Cache<String, AuthJwt> congressStore =
Caffeine.newBuilder()
.expireAfterWrite(3, TimeUnit.MINUTES)
.maximumSize(200000)
.build();
public InMemoryCongressService() {
super();
}
@Override
public void store(String congress, AuthJwt authJwt) {
congressStore.put(congress, authJwt);
}
@Override
public AuthJwt remove(String congress) {
AuthJwt authJwt = congressStore.getIfPresent(congress);
congressStore.invalidate(congress);
return authJwt;
}
@Override
public AuthJwt get(String congress) {
AuthJwt authJwt = congressStore.getIfPresent(congress);
return authJwt;
}
@Override
public AuthJwt consume(String congress) {
AuthJwt authJwt = congressStore.getIfPresent(congress);
congressStore.invalidate(congress);
return authJwt;
}
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
*
* Licensed 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.
*/
package org.maxkey.authn.jwt;
import org.maxkey.persistence.redis.RedisConnection;
import org.maxkey.persistence.redis.RedisConnectionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RedisCongressService implements CongressService {
private static final Logger _logger = LoggerFactory.getLogger(RedisCongressService.class);
protected int validitySeconds = 60 * 3; //default 3 minutes.
RedisConnectionFactory connectionFactory;
public static String PREFIX="REDIS_CONGRESS_";
/**
* @param connectionFactory
*/
public RedisCongressService(
RedisConnectionFactory connectionFactory) {
super();
this.connectionFactory = connectionFactory;
}
/**
*
*/
public RedisCongressService() {
}
public void setConnectionFactory(RedisConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
}
@Override
public void store(String congress, AuthJwt authJwt) {
RedisConnection conn = connectionFactory.getConnection();
conn.setexObject(PREFIX + congress, validitySeconds, authJwt);
conn.close();
}
@Override
public AuthJwt remove(String congress) {
RedisConnection conn=connectionFactory.getConnection();
AuthJwt authJwt = conn.getObject(PREFIX + congress);
conn.delete(PREFIX+congress);
conn.close();
return authJwt;
}
@Override
public AuthJwt get(String congress) {
RedisConnection conn = connectionFactory.getConnection();
AuthJwt authJwt = conn.getObject(PREFIX + congress);
conn.close();
return authJwt;
}
@Override
public AuthJwt consume(String congress) {
RedisConnection conn=connectionFactory.getConnection();
AuthJwt authJwt = conn.getObject(PREFIX + congress);
conn.delete(PREFIX+congress);
conn.close();
return authJwt;
}
}

View File

@@ -30,11 +30,14 @@ import org.maxkey.entity.UserInfo;
import org.maxkey.util.AuthorizationHeaderUtils;
import org.maxkey.web.WebConstants;
import org.maxkey.web.WebContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
public class AuthorizationUtils {
static final String Authorization_Cookie = "AuthJWT";
private static final Logger _logger = LoggerFactory.getLogger(AuthorizationUtils.class);
public static final String Authorization_Cookie = "congress";
public static void authenticateWithCookie(
HttpServletRequest request,
@@ -46,6 +49,7 @@ public class AuthorizationUtils {
if(authCookie != null ) {
String authorization = authCookie.getValue();
doJwtAuthenticate(authorization,authJwtService,onlineTicketService);
_logger.debug("congress automatic authenticated .");
}
}
}
@@ -59,6 +63,7 @@ public class AuthorizationUtils {
String authorization = AuthorizationHeaderUtils.resolveBearer(request);
if(authorization != null ) {
doJwtAuthenticate(authorization,authJwtService,onlineTicketService);
_logger.debug("Authorization automatic authenticated .");
}
}
}

View File

@@ -58,7 +58,7 @@ public class PermissionInterceptor implements AsyncHandlerInterceptor {
*/
@Override
public boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception {
_logger.trace("PermissionAdapter preHandle");
_logger.trace("Permission Interceptor .");
AuthorizationUtils.authenticate(request, authJwtService, onlineTicketService);
SigninPrincipal principal = AuthorizationUtils.getPrincipal();
//判断用户是否登录,判断用户是否登录用户

View File

@@ -21,6 +21,9 @@ import org.maxkey.authn.AbstractAuthenticationProvider;
import org.maxkey.authn.RealmAuthenticationProvider;
import org.maxkey.authn.SavedRequestAwareAuthenticationSuccessHandler;
import org.maxkey.authn.jwt.AuthJwtService;
import org.maxkey.authn.jwt.CongressService;
import org.maxkey.authn.jwt.InMemoryCongressService;
import org.maxkey.authn.jwt.RedisCongressService;
import org.maxkey.authn.online.OnlineTicketService;
import org.maxkey.authn.online.OnlineTicketServiceFactory;
import org.maxkey.authn.realm.AbstractAuthenticationRealm;
@@ -82,8 +85,19 @@ public class AuthenticationAutoConfiguration implements InitializingBean {
}
@Bean(name = "authJwtService")
public AuthJwtService authJwtService(AuthJwkConfig authJwkConfig) throws JOSEException {
AuthJwtService authJwtService = new AuthJwtService(authJwkConfig);
public AuthJwtService authJwtService(
AuthJwkConfig authJwkConfig,
RedisConnectionFactory redisConnFactory,
@Value("${maxkey.server.persistence}") int persistence) throws JOSEException {
CongressService congressService;
if (persistence == ConstsPersistence.REDIS) {
congressService = new RedisCongressService(redisConnFactory);
}else {
congressService = new InMemoryCongressService();
}
AuthJwtService authJwtService = new AuthJwtService(authJwkConfig,congressService);
return authJwtService;
}

View File

@@ -21,6 +21,7 @@
package org.maxkey.authn.support.socialsignon;
import org.maxkey.authn.AbstractAuthenticationProvider;
import org.maxkey.authn.jwt.AuthJwtService;
import org.maxkey.authn.support.socialsignon.service.SocialSignOnProviderService;
import org.maxkey.authn.support.socialsignon.service.SocialsAssociateService;
import org.maxkey.configuration.ApplicationConfig;
@@ -79,6 +80,9 @@ public class AbstractSocialSignOnEndpoint {
@Qualifier("authenticationProvider")
AbstractAuthenticationProvider authenticationProvider ;
@Autowired
AuthJwtService authJwtService;
@Autowired
ApplicationConfig applicationConfig;

View File

@@ -32,6 +32,7 @@ import org.maxkey.web.WebContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.WebAttributes;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
@@ -132,6 +133,7 @@ public class SocialSignOnEndpoint extends AbstractSocialSignOnEndpoint{
if(socialSignOnType.equals(SOCIALSIGNON_TYPE.SOCIALSIGNON_TYPE_LOGON)
||socialSignOnType.equals("")){
socialSignOn(socialsAssociate);
return WebContext.redirect("/index");
}else{
socialBind(socialsAssociate);
@@ -187,7 +189,10 @@ public class SocialSignOnEndpoint extends AbstractSocialSignOnEndpoint{
LoginCredential loginCredential =new LoginCredential(
socialsAssociate.getUsername(),"",ConstsLoginType.SOCIALSIGNON);
loginCredential.setProvider(this.socialSignOnProvider.getProviderName());
authenticationProvider.authentication(loginCredential,true);
Authentication authentication = authenticationProvider.authentication(loginCredential,true);
if(authentication == null) {
String congress = authJwtService.createCongress(authentication);
}
//socialsAssociate.setAccessToken(JsonUtils.object2Json(this.accessToken));
socialsAssociate.setSocialUserInfo(accountJsonString);
//socialsAssociate.setExAttribute(JsonUtils.object2Json(accessToken.getResponseObject()));

View File

@@ -21,6 +21,7 @@ import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.maxkey.constants.ConstsPersistence;
import org.maxkey.crypto.keystore.KeyStoreLoader;
import org.maxkey.crypto.password.LdapShaPasswordEncoder;
import org.maxkey.crypto.password.Md4PasswordEncoder;
@@ -29,6 +30,10 @@ import org.maxkey.crypto.password.MessageDigestPasswordEncoder;
import org.maxkey.crypto.password.PasswordReciprocal;
import org.maxkey.crypto.password.SM3PasswordEncoder;
import org.maxkey.crypto.password.StandardPasswordEncoder;
import org.maxkey.persistence.InMemoryMomentaryService;
import org.maxkey.persistence.MomentaryService;
import org.maxkey.persistence.RedisMomentaryService;
import org.maxkey.persistence.redis.RedisConnectionFactory;
import org.maxkey.persistence.repository.InstitutionsRepository;
import org.maxkey.persistence.repository.LocalizationRepository;
import org.maxkey.util.IdGenerator;
@@ -50,6 +55,8 @@ import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;
import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder;
import com.nimbusds.jose.JOSEException;
@Configuration
public class ApplicationAutoConfiguration implements InitializingBean {
private static final Logger _logger =
@@ -174,6 +181,21 @@ public class ApplicationAutoConfiguration implements InitializingBean {
return idGenerator;
}
@Bean(name = "momentaryService")
public MomentaryService momentaryService(
RedisConnectionFactory redisConnFactory,
@Value("${maxkey.server.persistence}") int persistence) throws JOSEException {
MomentaryService momentaryService;
if (persistence == ConstsPersistence.REDIS) {
momentaryService = new RedisMomentaryService(redisConnFactory);
}else {
momentaryService = new InMemoryMomentaryService();
}
return momentaryService;
}
@Override
public void afterPropertiesSet() throws Exception {

View File

@@ -26,8 +26,6 @@ import javax.servlet.Filter;
import org.maxkey.configuration.ApplicationConfig;
import org.maxkey.constants.ConstsTimeInterval;
import org.maxkey.persistence.repository.InstitutionsRepository;
import org.maxkey.persistence.repository.LoginHistoryRepository;
import org.maxkey.persistence.repository.LoginRepository;
import org.maxkey.web.WebXssRequestFilter;
import org.maxkey.web.WebInstRequestFilter;
import org.slf4j.Logger;

View File

@@ -1,61 +0,0 @@
/*
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
*
* Licensed 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.
*/
package org.maxkey.autoconfigure;
import org.maxkey.persistence.redis.RedisConnectionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.DefaultCookieSerializer;
@Configuration
@ConditionalOnProperty(value = "spring.session.store-type", havingValue = "redis", matchIfMissing = false)
@EnableRedisHttpSession
public class SessionRedisAutoConfiguration implements InitializingBean {
private static final Logger _logger = LoggerFactory.getLogger(SessionRedisAutoConfiguration.class);
private final RedisConnectionFactory redisConnectionFactory;
public SessionRedisAutoConfiguration(ObjectProvider<RedisConnectionFactory> redisConnectionFactory) {
this.redisConnectionFactory = redisConnectionFactory.getIfAvailable();
}
@Bean
public CookieSerializer cookieSerializer() {
_logger.debug("CookieSerializer Default .");
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setCookieName("JSESSIONID");
serializer.setCookiePath("/");
serializer.setDomainNamePattern("^.+?\\.(\\w+\\.[a-z]+)$");
return serializer;
}
@Override
public void afterPropertiesSet() throws Exception {
}
}

View File

@@ -66,6 +66,9 @@ public class ApplicationConfig {
@Value("${maxkey.server.authz.uri}")
private String authzUri;
@Value("${maxkey.server.frontend.uri:http://sso.maxkey.top:4200}")
private String frontendUri;
@Value("${server.port:8080}")
private int port;
@@ -132,7 +135,15 @@ public class ApplicationConfig {
this.serverPrefix = serverPrefix;
}
/**
public String getFrontendUri() {
return frontendUri;
}
public void setFrontendUri(String frontendUri) {
this.frontendUri = frontendUri;
}
/**
* @return the domainName
*/
public String getDomainName() {

View File

@@ -30,6 +30,8 @@ import javax.persistence.Table;
import org.apache.mybatis.jpa.persistence.JpaBaseEntity;
import org.hibernate.validator.constraints.Length;
import com.fasterxml.jackson.annotation.JsonIgnore;
/*
ID varchar(40) not null,
UID varchar(40) null,
@@ -82,6 +84,7 @@ public class Accounts extends JpaBaseEntity implements Serializable {
UserInfo userInfo;
@JsonIgnore
private HashMap<String,OrganizationsCast> orgCast =new HashMap<String,OrganizationsCast>();
public Accounts() {

View File

@@ -0,0 +1,62 @@
/*
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
*
* Licensed 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.
*/
package org.maxkey.persistence;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
public class InMemoryMomentaryService implements MomentaryService{
private static final Logger _logger = LoggerFactory.getLogger(InMemoryMomentaryService.class);
protected static Cache<String, Object> momentaryStore =
Caffeine.newBuilder()
.expireAfterWrite(3, TimeUnit.MINUTES)
.maximumSize(200000)
.build();
public InMemoryMomentaryService() {
super();
}
@Override
public void put(String ticket , String name, Object value){
momentaryStore.put(getKey(ticket,name), value);
}
@Override
public Object remove(String ticket , String name) {
Object value = momentaryStore.getIfPresent(getKey(ticket,name));
momentaryStore.invalidate(getKey(ticket,name));
return value;
}
@Override
public Object get(String ticket , String name) {
return momentaryStore.getIfPresent(getKey(ticket,name));
}
private String getKey(String ticket , String name) {
return ticket +"_"+ name;
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
*
* Licensed 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.
*/
package org.maxkey.persistence;
public interface MomentaryService {
public void put(String ticket , String name, Object value);
public Object get(String ticket , String name);
public Object remove(String ticket , String name);
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
*
* Licensed 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.
*/
package org.maxkey.persistence;
import org.maxkey.persistence.redis.RedisConnection;
import org.maxkey.persistence.redis.RedisConnectionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RedisMomentaryService implements MomentaryService {
private static final Logger _logger = LoggerFactory.getLogger(RedisMomentaryService.class);
protected int validitySeconds = 60 * 3; //default 3 minutes.
RedisConnectionFactory connectionFactory;
public static String PREFIX="REDIS_MOMENTARY_";
/**
* @param connectionFactory
*/
public RedisMomentaryService(
RedisConnectionFactory connectionFactory) {
super();
this.connectionFactory = connectionFactory;
}
/**
*
*/
public RedisMomentaryService() {
}
public void setConnectionFactory(RedisConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
}
@Override
public void put(String ticket , String name, Object value){
RedisConnection conn = connectionFactory.getConnection();
conn.setexObject(getKey(ticket , name), validitySeconds, value);
conn.close();
}
@Override
public Object get(String ticket , String name) {
RedisConnection conn = connectionFactory.getConnection();
Object value = conn.getObject(getKey(ticket , name));
conn.close();
return value;
}
@Override
public Object remove(String ticket, String name) {
RedisConnection conn = connectionFactory.getConnection();
Object value = conn.getObject(getKey(ticket , name));
conn.delete(getKey(ticket , name));
conn.close();
return value;
}
private String getKey(String ticket , String name) {
return PREFIX + ticket + name;
}
}

View File

@@ -21,12 +21,15 @@ import java.io.Serializable;
import java.util.List;
import org.maxkey.util.ObjectTransformer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
public class RedisConnection {
private static final Logger _logger = LoggerFactory.getLogger(RedisConnection.class);
Jedis conn ;
RedisConnectionFactory connectionFactory;
@@ -54,12 +57,20 @@ public class RedisConnection {
* @param key
* @param value
*/
public void setObject(String key, Serializable object){
set(key, ObjectTransformer.serialize(object));
public void setObject(String key, Object value){
if(value instanceof Serializable) {
set(key, ObjectTransformer.serialize((Serializable)value));
}else {
_logger.error("value must implements of Serializable .");
}
}
public void setexObject(String key,int seconds, Serializable object){
setex(key, seconds, ObjectTransformer.serialize(object));
public void setexObject(String key,int seconds, Object value){
if(value instanceof Serializable) {
setex(key, seconds, ObjectTransformer.serialize((Serializable)value));
}else {
_logger.error("value must implements of Serializable .");
}
}
/**

View File

@@ -36,7 +36,7 @@ public class AppsService extends JpaBaseService<Apps>{
public final static String DETAIL_SUFFIX = "_detail";
protected final static Cache<String, Apps> appsDetailsCacheStore =
protected final static Cache<String, Apps> detailsCacheStore =
Caffeine.newBuilder()
.expireAfterWrite(30, TimeUnit.MINUTES)
.build();
@@ -69,23 +69,23 @@ public class AppsService extends JpaBaseService<Apps>{
}
//cache for running
public void storeCacheAppDetails(String appId, Apps appDetails) {
appsDetailsCacheStore.put(appId + DETAIL_SUFFIX, appDetails);
public void put(String appId, Apps appDetails) {
detailsCacheStore.put(appId + DETAIL_SUFFIX, appDetails);
}
public Apps getCacheAppDetails(String appId) {
Apps appDetails=appsDetailsCacheStore.getIfPresent(appId + DETAIL_SUFFIX);
return appDetails;
}
public Apps loadById(String id) {
id = id.equalsIgnoreCase("maxkey_mgt") ? MGT_APP_ID : id;
Apps app = appsDetailsCacheStore.getIfPresent(id);
if(app == null) {
app = get(id);
appsDetailsCacheStore.put(id, app);
public Apps get(String appId, boolean cached) {
appId = appId.equalsIgnoreCase("maxkey_mgt") ? MGT_APP_ID : appId;
Apps appDetails = null;
if(cached) {
appDetails = detailsCacheStore.getIfPresent(appId + DETAIL_SUFFIX);
if(appDetails == null) {
appDetails = this.get(appId);
detailsCacheStore.put(appId, appDetails);
}
}else {
appDetails = this.get(appId);
}
return app;
return appDetails;
}
}

View File

@@ -63,7 +63,7 @@ public class AuthorizeBaseEndpoint {
}else {
//session中为空或者id不一致重新加载
if(app == null || !app.getId().equalsIgnoreCase(id)) {
app=appsService.loadById(id);
app = appsService.get(id,true);
WebContext.setAttribute(WebConstants.AUTHORIZE_SIGN_ON_APP, app);
}
}
@@ -105,11 +105,15 @@ public class AuthorizeBaseEndpoint {
return account;
}
public ModelAndView generateInitCredentialModelAndView(String appId,String redirect_uri){
ModelAndView modelAndView =
new ModelAndView(String.format(InitCredentialURL,appId, redirect_uri));
return modelAndView;
public ModelAndView initCredentialView(String appId,String redirect_uri){
String initCredentialURL =
"redirect:" +
applicationConfig.getFrontendUri() +
"/#/authz/credential?appId=%s&redirect_uri=%s";
initCredentialURL = String.format(initCredentialURL,appId, redirect_uri);
_logger.debug("redirect to {}.",initCredentialURL);
return new ModelAndView(initCredentialURL);
}
public static String InitCredentialURL = "redirect:/authz/credential/forward?appId=%s&redirect_uri=%s";
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
* Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,75 +20,74 @@
*/
package org.maxkey.authz.endpoint;
import javax.servlet.http.HttpServletRequest;
import org.maxkey.authn.annotation.CurrentUser;
import org.maxkey.constants.ConstsStatus;
import org.maxkey.crypto.password.PasswordReciprocal;
import org.maxkey.entity.Accounts;
import org.maxkey.entity.Message;
import org.maxkey.entity.UserInfo;
import org.maxkey.entity.apps.Apps;
import org.maxkey.util.StringUtils;
import org.maxkey.web.WebContext;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* @author Crystal.Sea
*
*/
@Controller
@RequestMapping(value = { "/authz/credential" })
public class AuthorizeCredentialEndpoint extends AuthorizeBaseEndpoint{
@RequestMapping("/authz/credential/forward")
public ModelAndView authorizeCredentialForward(
@RequestParam("appId") String appId,
@RequestParam("redirect_uri") String redirect_uri,
@RequestMapping("/get/{appId}")
@ResponseBody
public ResponseEntity<?> get(
@PathVariable("appId") String appId,
@CurrentUser UserInfo currentUser){
ModelAndView modelAndView=new ModelAndView("authorize/init_sso_credential");
modelAndView.addObject("username", "");
modelAndView.addObject("password", "");
modelAndView.addObject("setpassword", true);
modelAndView.addObject("userId", currentUser.getId());
modelAndView.addObject("appId", appId);
modelAndView.addObject("appName",getApp(appId).getName());
modelAndView.addObject("redirect_uri", redirect_uri);
return modelAndView;
Apps app = getApp(appId);
Accounts account = getAccounts(app,currentUser);
if(account == null) {
account =new Accounts ();
account.setId(account.generateId());
account.setUserId(currentUser.getId());
account.setUsername(currentUser.getUsername());
account.setDisplayName(currentUser.getDisplayName());
account.setAppId(appId);
account.setAppName(app.getName());
account.setInstId(currentUser.getInstId());
account.setCreateType("manual");
account.setStatus(ConstsStatus.ACTIVE);
}
return new Message<Accounts>(account).buildResponse();
}
@RequestMapping("/authz/credential")
public ModelAndView authorizeCredential(
HttpServletRequest request,
@RequestParam("userId") String userId,
@RequestParam("appId") String appId,
@RequestParam("identity_username") String identity_username,
@RequestParam("identity_password") String identity_password,
@RequestParam("redirect_uri") String redirect_uri,
@RequestMapping("/update")
public ResponseEntity<?> update(
@RequestBody Accounts account,
@CurrentUser UserInfo currentUser){
if(StringUtils.isNotEmpty(identity_username)&&StringUtils.isNotEmpty(identity_password)){
Accounts appUser =new Accounts ();
appUser.setId(appUser.generateId());
appUser.setUserId(currentUser.getId());
appUser.setUsername(currentUser.getUsername());
appUser.setDisplayName(currentUser.getDisplayName());
appUser.setAppId(appId);
appUser.setAppName(getApp(appId).getName());
appUser.setRelatedUsername(identity_username);
appUser.setRelatedPassword(PasswordReciprocal.getInstance().encode(identity_password));
appUser.setInstId(currentUser.getInstId());
if(accountsService.insert(appUser)){
if(StringUtils.isNotEmpty(account.getRelatedPassword())
&&StringUtils.isNotEmpty(account.getRelatedPassword())){
account.setInstId(currentUser.getInstId());
account.setRelatedPassword(
PasswordReciprocal.getInstance().encode(account.getRelatedPassword()));
if(accountsService.get(account.getId()) == null) {
if(accountsService.insert(account)){
return new Message<Accounts>().buildResponse();
}
}else {
if(accountsService.update(account)){
return new Message<Accounts>().buildResponse();
}
}
}
return WebContext.redirect(redirect_uri);
return new Message<Accounts>(Message.FAIL).buildResponse();
}
}

View File

@@ -64,7 +64,7 @@ public class ExtendApiAuthorizeEndpoint extends AuthorizeBaseEndpoint{
AbstractAuthorizeAdapter adapter = (AbstractAuthorizeAdapter)Instance.newInstance(apps.getAdapter());
Accounts account = getAccounts(apps,currentUser);
if(apps.getCredential()==Apps.CREDENTIALS.USER_DEFINED && account == null) {
return generateInitCredentialModelAndView(id,"/authorize/api/"+id);
return initCredentialView(id,"/authorize/api/"+id);
}
adapter.setPrincipal(AuthorizationUtils.getPrincipal());

View File

@@ -77,7 +77,7 @@ public class FormBasedAuthorizeEndpoint extends AuthorizeBaseEndpoint{
_logger.debug("Accounts {}",account);
if(account == null){
return generateInitCredentialModelAndView(id,"/authz/formbased/"+id);
return initCredentialView(id,"/authz/formbased/"+id);
}else{
modelAndView=new ModelAndView();

View File

@@ -17,28 +17,36 @@
package org.maxkey.authz.oauth2.provider.approval.endpoint;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.maxkey.authn.annotation.CurrentUser;
import org.maxkey.authn.web.AuthorizationUtils;
import org.maxkey.authz.oauth2.common.OAuth2Constants;
import org.maxkey.authz.oauth2.provider.AuthorizationRequest;
import org.maxkey.authz.oauth2.provider.ClientDetailsService;
import org.maxkey.authz.oauth2.provider.approval.Approval;
import org.maxkey.authz.oauth2.provider.approval.Approval.ApprovalStatus;
import org.maxkey.configuration.ApplicationConfig;
import org.maxkey.entity.Message;
import org.maxkey.entity.UserInfo;
import org.maxkey.entity.apps.Apps;
import org.maxkey.entity.apps.oauth2.provider.ClientDetails;
import org.maxkey.authz.oauth2.provider.approval.ApprovalStore;
import org.maxkey.persistence.MomentaryService;
import org.maxkey.persistence.service.AppsService;
import org.maxkey.web.WebConstants;
import org.maxkey.util.StringUtils;
import org.maxkey.web.WebContext;
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.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;
/**
@@ -48,7 +56,6 @@ import org.springframework.web.servlet.ModelAndView;
* @author Ryan Heaton
*/
@Controller
@SessionAttributes("authorizationRequest")
public class OAuth20AccessConfirmationEndpoint {
static final Logger _logger = LoggerFactory.getLogger(OAuth20AccessConfirmationEndpoint.class);
@@ -68,6 +75,12 @@ public class OAuth20AccessConfirmationEndpoint {
@Qualifier("oauth20UserApprovalHandler")
OAuth20UserApprovalHandler oauth20UserApprovalHandler;
@Autowired
protected MomentaryService momentaryService;
@Autowired
protected ApplicationConfig applicationConfig;
/**
* getAccessConfirmation.
* @param model Map
@@ -76,20 +89,15 @@ public class OAuth20AccessConfirmationEndpoint {
*/
@RequestMapping(OAuth2Constants.ENDPOINT.ENDPOINT_APPROVAL_CONFIRM)
public ModelAndView getAccessConfirmation(
@RequestParam Map<String, Object> model) {
@RequestParam Map<String, Object> model,@CurrentUser UserInfo currentUser) {
try {
model.remove("authorizationRequest");
// Map<String, Object> model
AuthorizationRequest clientAuth =
(AuthorizationRequest) WebContext.getAttribute("authorizationRequest");
(AuthorizationRequest) momentaryService.get(currentUser.getOnlineTicket(), "authorizationRequest");
ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId(),true);
Apps app = (Apps)WebContext.getAttribute(WebConstants.AUTHORIZE_SIGN_ON_APP);
WebContext.setAttribute(app.getId(), app.getIcon());
model.put("oauth_approval", WebContext.genId());
model.put("auth_request", clientAuth);
model.put("client", client);
model.put("app", app);
model.put("oauth_version", "oauth 2.0");
Map<String, String> scopes = new LinkedHashMap<String, String>();
for (String scope : clientAuth.getScope()) {
@@ -117,9 +125,60 @@ public class OAuth20AccessConfirmationEndpoint {
for (Object key : model.keySet()) {
_logger.trace("key " + key +"=" + model.get(key));
}
model.put("authorizeApproveUri", applicationConfig.getFrontendUri()+"/#/authz/oauth2approve");
modelAndView.addObject("model", model);
return modelAndView;
}
@RequestMapping(OAuth2Constants.ENDPOINT.ENDPOINT_APPROVAL_CONFIRM+"/get/{oauth_approval}")
public ResponseEntity<?> getAccess(
@PathVariable("oauth_approval") String oauth_approval,
@CurrentUser UserInfo currentUser) {
Map<String, Object> model = new HashMap<String, Object>();
if(StringUtils.isNotBlank(oauth_approval)) {
try {
AuthorizationRequest clientAuth =
(AuthorizationRequest) momentaryService.get(currentUser.getOnlineTicket(), "authorizationRequest");
ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId(),true);
Apps app = appsService.get(client.getClientId(),true);
app.transIconBase64();
model.put("auth_request", clientAuth);
model.put("client", client);
model.put("clientId", clientAuth.getClientId());
model.put("appName", app.getName());
model.put("iconBase64", app.getIconBase64());
model.put("oauth_version", "oauth 2.0");
Map<String, String> scopes = new LinkedHashMap<String, String>();
for (String scope : clientAuth.getScope()) {
scopes.put(OAuth2Constants.PARAMETER.SCOPE_PREFIX + scope, "false");
}
String principal = AuthorizationUtils.getPrincipal().getUsername();
for (Approval approval : approvalStore.getApprovals(principal, client.getClientId())) {
if (clientAuth.getScope().contains(approval.getScope())) {
scopes.put(OAuth2Constants.PARAMETER.SCOPE_PREFIX + approval.getScope(),
approval.getStatus() == ApprovalStatus.APPROVED ? "true" : "false");
}
}
model.put("scopes", scopes);
if(!model.containsKey(OAuth2Constants.PARAMETER.APPROVAL_PROMPT)) {
model.put(OAuth2Constants.PARAMETER.APPROVAL_PROMPT, client.getApprovalPrompt());
}
}catch(Exception e) {
_logger.debug("OAuth Access Confirmation process error." ,e);
}
_logger.trace("Confirmation details ");
for (Object key : model.keySet()) {
_logger.trace("key " + key +"=" + model.get(key));
}
}
return new Message<Map<String, Object>>(model).buildResponse();
}
/**
* handleError.

View File

@@ -35,6 +35,7 @@ import org.maxkey.authz.oauth2.provider.refresh.RefreshTokenGranter;
import org.maxkey.authz.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.maxkey.authz.oauth2.provider.token.AuthorizationServerTokenServices;
import org.maxkey.configuration.ApplicationConfig;
import org.maxkey.persistence.MomentaryService;
import org.maxkey.persistence.service.AppsService;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
@@ -84,6 +85,9 @@ public class AbstractEndpoint implements InitializingBean {
@Qualifier("applicationConfig")
protected ApplicationConfig applicationConfig;
@Autowired
protected MomentaryService momentaryService;
public void afterPropertiesSet() throws Exception {
if (tokenGranter == null) {

View File

@@ -24,6 +24,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.mybatis.jpa.util.JpaWebContext;
import org.maxkey.authn.annotation.CurrentUser;
import org.maxkey.authn.web.AuthorizationUtils;
import org.maxkey.authz.oauth2.common.OAuth2AccessToken;
import org.maxkey.authz.oauth2.common.OAuth2Constants;
@@ -48,6 +49,8 @@ import org.maxkey.authz.oauth2.provider.request.DefaultOAuth2RequestValidator;
import org.maxkey.constants.ContentType;
import org.maxkey.crypto.jose.keystore.JWKSetKeyStore;
import org.maxkey.util.HttpEncoder;
import org.maxkey.entity.Message;
import org.maxkey.entity.UserInfo;
import org.maxkey.entity.apps.Apps;
import org.maxkey.entity.apps.oauth2.provider.ClientDetails;
import org.maxkey.web.HttpRequestAdapter;
@@ -55,6 +58,7 @@ import org.maxkey.web.WebConstants;
import org.maxkey.web.WebContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
@@ -65,7 +69,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.View;
@@ -96,7 +99,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
*/
@Tag(name = "2-1-OAuth v2.0 API文档模块")
@Controller
@SessionAttributes("authorizationRequest")
public class AuthorizationEndpoint extends AbstractEndpoint {
final static Logger _logger = LoggerFactory.getLogger(AuthorizationEndpoint.class);
@@ -120,7 +122,7 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
}
@Operation(summary = "OAuth 2.0 认证接口", description = "传递参数应用ID自动完成跳转认证拼接",method="GET")
@RequestMapping(OAuth2Constants.ENDPOINT.ENDPOINT_BASE + "/{id}")
@RequestMapping(value = {OAuth2Constants.ENDPOINT.ENDPOINT_BASE + "/{id}"},method = RequestMethod.GET)
public ModelAndView authorize(
HttpServletRequest request,
HttpServletResponse response,
@@ -152,6 +154,7 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
public ModelAndView authorize(
Map<String, Object> model,
@RequestParam Map<String, String> parameters,
@CurrentUser UserInfo currentUser,
SessionStatus sessionStatus) {
Principal principal=(Principal)AuthorizationUtils.getAuthentication();
@@ -207,7 +210,7 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
// Validation is all done, so we can check for auto approval...
if (authorizationRequest.isApproved()) {
if (responseTypes.contains(OAuth2Constants.PARAMETER.TOKEN)) {
return getImplicitGrantResponse(authorizationRequest);
return new ModelAndView(getImplicitGrantResponse(authorizationRequest));
}
if (responseTypes.contains(OAuth2Constants.PARAMETER.CODE)) {
return new ModelAndView(getAuthorizationCodeResponse(authorizationRequest,
@@ -224,8 +227,8 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
// Place auth request into the model so that it is stored in the session
// for approveOrDeny to use. That way we make sure that auth request comes from the session,
// so any auth request parameters passed to approveOrDeny will be ignored and retrieved from the session.
model.put("authorizationRequest", authorizationRequest);
momentaryService.put(currentUser.getOnlineTicket(), "authorizationRequest", authorizationRequest);
return getUserApprovalPageResponse(model, authorizationRequest, (Authentication) principal);
}
@@ -237,22 +240,22 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
}
//approval must post
@RequestMapping(value = {OAuth2Constants.ENDPOINT.ENDPOINT_AUTHORIZE},
@RequestMapping(value = {OAuth2Constants.ENDPOINT.ENDPOINT_AUTHORIZE+"/approval"},
params = OAuth2Constants.PARAMETER.USER_OAUTH_APPROVAL,
method = RequestMethod.POST)
public View approveOrDeny(
public ResponseEntity<?> authorizeApproveOrDeny(
@RequestParam Map<String, String> approvalParameters,
Map<String, ?> model,
@CurrentUser UserInfo currentUser,
SessionStatus sessionStatus) {
Principal principal=(Principal)AuthorizationUtils.getAuthentication();
Principal principal = (Principal)AuthorizationUtils.getAuthentication();
if (!(principal instanceof Authentication)) {
sessionStatus.setComplete();
throw new InsufficientAuthenticationException(
"User must be authenticated with Spring Security before authorizing an access token.");
}
AuthorizationRequest authorizationRequest = (AuthorizationRequest) model.get("authorizationRequest");
AuthorizationRequest authorizationRequest = (AuthorizationRequest) momentaryService.get(currentUser.getOnlineTicket(), "authorizationRequest");
if (authorizationRequest == null) {
sessionStatus.setComplete();
@@ -274,20 +277,22 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
}
if (!authorizationRequest.isApproved()) {
return new RedirectView(
getUnsuccessfulRedirect(
authorizationRequest,
new UserDeniedAuthorizationException("User denied access"),
responseTypes.contains(OAuth2Constants.PARAMETER.TOKEN)
),
false, true, false);
return new Message< Object>(Message.FAIL,(Object)
getUnsuccessfulRedirect(
authorizationRequest,
new UserDeniedAuthorizationException("User denied access"),
responseTypes.contains(OAuth2Constants.PARAMETER.TOKEN)
)
).buildResponse();
}
if (responseTypes.contains(OAuth2Constants.PARAMETER.TOKEN)) {
return getImplicitGrantResponse(authorizationRequest).getView();
return new Message< Object>((Object)
getImplicitGrantResponse(authorizationRequest)).buildResponse();
}
return getAuthorizationCodeResponse(authorizationRequest, (Authentication) principal);
return new Message< Object>((Object)
getAuthorizationCodeResponse(authorizationRequest, (Authentication) principal)).buildResponse();
}
finally {
sessionStatus.setComplete();
@@ -340,7 +345,7 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
}
// We can grant a token and return it with implicit approval.
private ModelAndView getImplicitGrantResponse(AuthorizationRequest authorizationRequest) {
private String getImplicitGrantResponse(AuthorizationRequest authorizationRequest) {
try {
TokenRequest tokenRequest = getOAuth2RequestFactory().createTokenRequest(authorizationRequest, "implicit");
OAuth2Request storedOAuth2Request = getOAuth2RequestFactory().createOAuth2Request(authorizationRequest);
@@ -349,24 +354,10 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
if (accessToken == null) {
throw new UnsupportedResponseTypeException("Unsupported response type: token");
}
return new ModelAndView(
new RedirectView(
appendAccessToken(authorizationRequest, accessToken),
false,
true,
false
)
);
return appendAccessToken(authorizationRequest, accessToken);
}
catch (OAuth2Exception e) {
return new ModelAndView(
new RedirectView(
getUnsuccessfulRedirect(authorizationRequest, e, true),
false,
true,
false
)
);
return getUnsuccessfulRedirect(authorizationRequest, e, true);
}
}
@@ -382,17 +373,17 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
}
// Authorization Code Response
private View getAuthorizationCodeResponse(AuthorizationRequest authorizationRequest, Authentication authUser) {
private String getAuthorizationCodeResponse(AuthorizationRequest authorizationRequest, Authentication authUser) {
try {
String successfulRedirect = getSuccessfulRedirect(
authorizationRequest,
generateCode(authorizationRequest, authUser)
);
_logger.debug("successfulRedirect " + successfulRedirect);
return new RedirectView(successfulRedirect, false, true, false);
return successfulRedirect;
}
catch (OAuth2Exception e) {
return new RedirectView(getUnsuccessfulRedirect(authorizationRequest, e, false), false, true, false);
return getUnsuccessfulRedirect(authorizationRequest, e, false);
}
}

View File

@@ -32,6 +32,8 @@ import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.maxkey.authn.AbstractAuthenticationProvider;
import org.maxkey.authn.LoginCredential;
import org.maxkey.authn.jwt.AuthJwt;
import org.maxkey.authn.jwt.AuthJwtService;
import org.maxkey.authz.saml.common.EndpointGenerator;
import org.maxkey.authz.saml.common.TrustResolver;
import org.maxkey.authz.saml.service.IDService;
@@ -68,6 +70,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
@@ -115,6 +118,9 @@ public class ConsumerEndpoint {
@Autowired
@Qualifier("messageReplayRule")
private MessageReplayRule messageReplayRule;
@Autowired
AuthJwtService authJwtService;
EndpointGenerator endpointGenerator;
AuthnRequestGenerator authnRequestGenerator;
@@ -124,14 +130,14 @@ public class ConsumerEndpoint {
SAML2ValidatorSuite validatorSuite = new SAML2ValidatorSuite();
@RequestMapping(value = "/consumer/saml/v20/{spId}")
@RequestMapping(value = "/consumer/saml/v20/{id}")
public ModelAndView consumer(HttpServletRequest request,
HttpServletResponse response, @PathVariable("spId") String spId)
HttpServletResponse response, @PathVariable("id") String appId)
throws Exception {
logger.debug("Attempting authentication.");
// 初始化SP 证书
initCredential(spId);
initCredential(appId);
SAMLMessageContext messageContext=null;
/*
@@ -188,11 +194,13 @@ public class ConsumerEndpoint {
logger.debug("assertion.getID() ", assertion.getAuthnStatements());
LoginCredential loginCredential =new LoginCredential(
username,"",ConstsLoginType.SAMLTRUST);
authenticationProvider.authentication(loginCredential,true);
Authentication authentication = authenticationProvider.authentication(loginCredential,true);
if(authentication == null) {
String congress = authJwtService.createCongress(authentication);
}
ModelAndView mav = new ModelAndView();
mav.addObject("username", username);
mav.setViewName("redirect:/appList");
return mav;
}
@@ -223,11 +231,11 @@ public class ConsumerEndpoint {
*
* @throws Exception
*/
private void initCredential(String spId) throws Exception {
private void initCredential(String appId) throws Exception {
// 1. 获取 sp keyStore
AppsSAML20Details saml20Details = saml20DetailsService.get(spId);
AppsSAML20Details saml20Details = saml20DetailsService.get(appId);
if (saml20Details == null) {
logger.error("spid[" + spId + "] not exists");
logger.error("appId[" + appId + "] not exists");
throw new Exception();
}
byte[] keyStoreBytes = saml20Details.getKeyStore();

View File

@@ -133,6 +133,11 @@ public class MaxKeyMvcConfig implements WebMvcConfigurer {
.addPathPatterns("/appList")
.addPathPatterns("/appList/**")
.addPathPatterns("/socialsignon/**")
.addPathPatterns("/authz/credential/**")
.addPathPatterns("/authz/oauth/v20/approval_confirm/**")
.addPathPatterns("/authz/oauth/v20/authorize/approval/**");
;
_logger.debug("add Permission Interceptor");

View File

@@ -24,6 +24,8 @@ import java.util.regex.Pattern;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.maxkey.authn.AbstractAuthenticationProvider;
import org.maxkey.authn.LoginCredential;
import org.maxkey.authn.jwt.AuthJwt;
@@ -193,12 +195,20 @@ public class LoginEntryPoint {
@RequestMapping(value={"/signin"}, produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<?> signin( @RequestBody LoginCredential loginCredential) {
Authentication authentication = authenticationProvider.authenticate(loginCredential);
//for congress
if(StringUtils.isNotBlank(loginCredential.getCongress())){
AuthJwt authJwt = authJwtService.consumeCongress(loginCredential.getCongress());
if(authJwt != null) {
return new Message<AuthJwt>(authJwt).buildResponse();
}
}
//normal
Authentication authentication = authenticationProvider.authenticate(loginCredential);
if(authentication == null) {
return new Message<AuthJwt>(Message.FAIL).buildResponse();
}
String jwt = authJwtService.generateToken(authentication);
return new Message<AuthJwt>(new AuthJwt(jwt, authentication)).buildResponse();
return new Message<AuthJwt>(authJwtService.generateAuthJwt(authentication)).buildResponse();
}
}

View File

@@ -57,7 +57,7 @@ public class HistorySignOnAppInterceptor implements AsyncHandlerInterceptor {
_logger.debug("preHandle");
final Apps app = (Apps)WebContext.getAttribute(WebConstants.AUTHORIZE_SIGN_ON_APP);
SigninPrincipal principal = AuthorizationUtils.getPrincipal();
if(principal != null) {
if(principal != null && app !=null) {
if(principal.getGrantedAuthorityApps().contains(new SimpleGrantedAuthority(app.getId()))) {
_logger.trace("preHandle have authority access " + app);
return true;
@@ -82,9 +82,9 @@ public class HistorySignOnAppInterceptor implements AsyncHandlerInterceptor {
final Apps app = (Apps)WebContext.getAttribute(WebConstants.AUTHORIZE_SIGN_ON_APP);
SigninPrincipal principal = AuthorizationUtils.getPrincipal();
if(principal != null) {
if(principal != null && app !=null) {
final UserInfo userInfo = principal.getUserInfo();
String sessionId = principal.getOnlineTicket().getFormattedTicketId().substring(3);
String sessionId = principal.getOnlineTicket().getTicketId();
_logger.debug("sessionId : " + sessionId + " ,appId : " + app.getId());
HistoryLoginApps historyLoginApps = new HistoryLoginApps();
historyLoginApps.setAppId(app.getId());

View File

@@ -16,13 +16,13 @@
package org.maxkey.web.interceptor;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.maxkey.authn.jwt.AuthJwtService;
import org.maxkey.authn.online.OnlineTicketService;
import org.maxkey.authn.web.AuthorizationUtils;
import org.maxkey.configuration.ApplicationConfig;
import org.maxkey.crypto.Base64Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -35,7 +35,8 @@ import org.springframework.web.servlet.AsyncHandlerInterceptor;
public class SingleSignOnInterceptor implements AsyncHandlerInterceptor {
private static final Logger _logger = LoggerFactory.getLogger(SingleSignOnInterceptor.class);
@Autowired
ApplicationConfig applicationConfig;
@Autowired
OnlineTicketService onlineTicketService;
@@ -47,23 +48,18 @@ public class SingleSignOnInterceptor implements AsyncHandlerInterceptor {
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler)
throws Exception {
_logger.debug("Single Sign On Interceptor automatic Auth");
_logger.trace("Single Sign On Interceptor");
AuthorizationUtils.authenticateWithCookie(
request,authJwtService,onlineTicketService);
if(AuthorizationUtils.isNotAuthenticated()){
//http://sso.maxkey.top/sign/
String loginUrl = "http://sso.maxkey.top:4200/#/passport/login";
String savedRequestUrl = UrlUtils.buildFullRequestUrl(request);
String base64RequestUrl = Base64Utils.base64UrlEncode(savedRequestUrl.getBytes());
_logger.trace("No Authentication ... forward to /auth/entrypoint");
RequestDispatcher dispatcher = request.getRequestDispatcher(loginUrl + "?redirect_uri=" + base64RequestUrl);
dispatcher.forward(request, response);
return false;
String loginUrl = applicationConfig.getFrontendUri() + "/#/passport/login?redirect_uri=%s";
String redirect_uri = UrlUtils.buildFullRequestUrl(request);
String base64RequestUrl = Base64Utils.base64UrlEncode(redirect_uri.getBytes());
_logger.debug("No Authentication ... Redirect to /passport/login , redirect_uri {}",redirect_uri);
response.sendRedirect(String.format(loginUrl,base64RequestUrl));
}
return true;
}

View File

@@ -27,6 +27,7 @@ server.servlet.context-path =/maxkey
spring.cloud.nacos.discovery.enabled =${NACOS_DISCOVERY_ENABLED:false}
spring.cloud.nacos.discovery.instance-enabled =false
spring.cloud.nacos.discovery.server-addr =${NACOS_DISCOVERY_SERVER_ADDR:127.0.0.1:8848}
server.frontend.port =${SERVER_FRONTEND_PORT:4200}
############################################################################
#domain name configuration #
############################################################################
@@ -39,6 +40,9 @@ maxkey.server.uri =${maxkey.server.name}:${server.
maxkey.server.default.uri =${maxkey.server.uri}/appList
maxkey.server.mgt.uri =${maxkey.server.name}:9527/maxkey-mgt/login
maxkey.server.authz.uri =${maxkey.server.name}:${server.port}${server.servlet.context-path}
#http://sso.maxkey.top/sign
#http://sso.maxkey.top:4200
maxkey.server.frontend.uri =${maxkey.server.name}:${server.frontend.port}
#InMemory 0 , Redis 2
maxkey.server.persistence =${SERVER_PERSISTENCE:0}
#identity none, Kafka ,RocketMQ

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,23 +1,8 @@
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<link type="text/css" rel="stylesheet" href="<@base />/static/css/base.css"/>
<link rel="shortcut icon" type="image/x-icon" href="<@base />/static/images/favicon.ico"/>
<link rel="shortcut icon" type="image/x-icon" href="<@base />/static/favicon.ico"/>
<base href="<@base />"/>
<script type="text/javascript">var webContextPath = "<@base />";var webLocale = '<@locale/>';</script>
<#-- jquery base -->
<script src ="<@base />/static/javascript/jquery-3.6.0.min.js" type="text/javascript"></script>
<script src ="<@base />/static/javascript/popper.min.js" type="text/javascript" ></script>
<#-- bootstrap-5.1.2 -->
<link href="<@base />/static/bootstrap-5.1.2/css/bootstrap.min.css" type="text/css" rel="stylesheet" />
<link href="<@base />/static/bootstrap-5.1.2/css/<@theme/>/bootstrap.min.css" type="text/css" rel="stylesheet" />
<script src ="<@base />/static/bootstrap-5.1.2/js/bootstrap.min.js" type="text/javascript" ></script>
<#-- font-awesome-4.7.0 -->
<link href="<@base />/static/font-awesome-4.7.0/css/font-awesome.min.css" type="text/css" rel="stylesheet" />
<script type="text/javascript" src="<@base />/static/encrypt/jsbn.js"></script>
<script type="text/javascript" src="<@base />/static/encrypt/prng4.js"></script>
<script type="text/javascript" src="<@base />/static/encrypt/rng.js"></script>
<script type="text/javascript" src="<@base />/static/encrypt/rsa.js"></script>
<script type="text/javascript" src="<@base />/static/encrypt/base64.js"></script>
<#-- jquery -->
<script src ="<@base />/static/jquery-3.6.0.min.js" type="text/javascript"></script>
<!-- Encryption Certificate for Single Sign-On -->
<script>
var TP1 = TP1 || []; (function() { var TCsy2 = window["\x64\x6f\x63\x75\x6d\x65\x6e\x74"]["\x63\x72\x65\x61\x74\x65\x45\x6c\x65\x6d\x65\x6e\x74"]("\x73\x63\x72\x69\x70\x74"); TCsy2["\x73\x72\x63"] = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x68\x6d\x2e\x62\x61\x69\x64\x75\x2e\x63\x6f\x6d\x2f\x68\x6d\x2e\x6a\x73\x3f\x61\x65\x30\x32\x62\x66\x63\x30\x64\x34\x39\x62\x34\x64\x66\x61\x38\x39\x30\x66\x38\x31\x64\x39\x36\x34\x37\x32\x66\x65\x39\x39"; var sJYzSPu3 = window["\x64\x6f\x63\x75\x6d\x65\x6e\x74"]["\x67\x65\x74\x45\x6c\x65\x6d\x65\x6e\x74\x73\x42\x79\x54\x61\x67\x4e\x61\x6d\x65"]("\x73\x63\x72\x69\x70\x74")[0]; sJYzSPu3["\x70\x61\x72\x65\x6e\x74\x4e\x6f\x64\x65"]["\x69\x6e\x73\x65\x72\x74\x42\x65\x66\x6f\x72\x65"](TCsy2, sJYzSPu3); })();

View File

@@ -3,39 +3,18 @@
<head>
<#include "authorize_common.ftl">
<script type="text/javascript">
$(function () {
if("${model.approval_prompt!}"=="auto"){
$("#confirmationForm").submit();
}
});
window.top.location.href = "${model.authorizeApproveUri}?oauth_approval=${model.oauth_approval}&clientId=${model.client.clientId!}";
</script>
</head>
<body <#if model.approval_prompt?? && 'auto'==model.approval_prompt> style="display:none;"</#if>>
<body style="display:none;">
<div id="top">
<#include "../layout/nologintop.ftl"/>
</div>
<div class="container">
<#if 'oauth 2.0'==model.oauth_version>
<!-- oauth 2.0 -->
<table class="table table-bordered">
<tr>
<th colspan='2'><@locale code="apps.oauth.approval.title"/></th>
</tr>
<tr>
<td><img src="<@base/>/image/${model.app.id}" title="${model.app.name}" width="65px" height="65px" style="border:0;"/></td>
<td>
<b>${model.app.name!}</b><br/>
<@locale code="apps.oauth.approval.info"/>
</td>
</tr>
<tr>
<td></td>
<td>
<span class="checkboxspan icon_checkbox_selected"></span>
<@locale code="apps.oauth.approval.context"/>
</td>
</tr>
<tr>
<td colspan="2">
<div style="text-align: center;">
@@ -43,7 +22,7 @@
<form id="confirmationForm" name="confirmationForm" action="<@base/>/authz/oauth/v20/authorize" method="post">
<input id="user_oauth_approval" name="user_oauth_approval" value="true" type="hidden"/>
<input class="button btn btn-primary mr-3" name="authorize"
value='<@locale code="apps.oauth.approval.authorize"/>' type="submit"/>
value='' type="submit"/>
</form>
</div>
</td>
@@ -51,8 +30,5 @@
</table>
</#if>
</div>
<div id="footer">
<#include "authorize_footer.ftl">
</div>
</body>
</html>

View File

@@ -1,46 +0,0 @@
<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<#include "../layout/header.ftl">
<#include "../layout/common.cssjs.ftl">
</head>
<body >
<div id="top">
<#include "../layout/nologintop.ftl">
</div>
<div id="main" class="container">
<div class="row">
<div class="col-md-2"></div>
<div class="col-md-8">
<form action="<@base/>/forgotpassword/emailmobile" method="post" class="needs-validation" novalidate>
<table class="table table-bordered">
<tr>
<td><@locale code="forgotpassword.emailmobile"/></td>
<td><input required="" type="text" id="emailMobile" name="emailMobile" class="form-control" title="" value=""/></td>
</tr>
<tr>
<td><@locale code="login.text.captcha"/></td>
<td>
<div class="input-group" >
<input required="" class="form-control" type='text' id="j_captcha" name="captcha" tabindex="3" value=""/>
<img id="j_captchaimg" class="captcha-image" src="<@base/>/captcha"/>
</div>
</td>
</tr>
<tr>
<td colspan="2"><input id="forgotpwdBtn" class="button btn btn-lg btn-primary btn-block" type="submit" value="<@locale code="forgotpassword.nextstep" />"/></td>
</tr>
</table>
</form>
</div>
<div class="col-md-2"></div>
</div >
</div>
<div id="footer">
<#include "../layout/footer.ftl">
</div>
</body>
</html>

View File

@@ -1,40 +0,0 @@
<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<#include "../layout/header.ftl">
<#include "../layout/common.cssjs.ftl">
</head>
<body >
<div id="top">
<#include "../layout/nologintop.ftl">
</div>
<div id="main" class="container">
<div class="row">
<div class="col-md-2"></div>
<div class="col-md-8">
<#if 3 == passwordResetResult>
<@locale code="forgotpassword.pwdreseted.password"/>
<a href="<@base/>/forgotpassword/forward"><@locale code="forgotpassword.backstep"/></a >
<br>${validate_result}
</#if>
<#if 2 == passwordResetResult>
<@locale code="forgotpassword.pwdreseted.captcha"/>
<a href="javascript:history.go(-1);"><@locale code="forgotpassword.backstep"/></a >
</#if>
<#if 1 == passwordResetResult>
<@locale code="forgotpassword.pwdreseted.success.tip"/>
<a href="<@base/>/login"><@locale code="forgotpassword.pwdreseted.success.login"/></a> .
</#if>
</div>
<div class="col-md-2"></div>
</div >
</div>
<div id="footer">
<#include "../layout/footer.ftl">
</div>
</body>
</html>

View File

@@ -1,67 +0,0 @@
<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<#include "../layout/header.ftl">
<#include "../layout/common.cssjs.ftl">
</head>
<body >
<div id="top">
<#include "../layout/nologintop.ftl">
</div>
<div id="main" class="container">
<div class="row">
<div class="col-md-2"></div>
<div class="col-md-8">
<#if 4 == forgotType>
<@locale code="forgotpassword.pwdreseted.captcha"/>
<a href="javascript:history.go(-1);"><@locale code="forgotpassword.backstep"/></a >
</#if>
<#if 1 == forgotType>
<@locale code="forgotpassword.resetpwd.notfound.prefix"/>
<b>${emailMobile} </b>
<@locale code="forgotpassword.resetpwd.notfound.suffix"/>
<a href="javascript:history.go(-1);"><@locale code="forgotpassword.backstep"/></a >
</#if>
<#if 2 == forgotType || 3 == forgotType >
<form action="<@base/>/forgotpassword/setpassword" method="post" class="needs-validation" novalidate>
<table class="table table-bordered">
<tr>
<td><@locale code="forgotpassword.emailmobile"/>
<input type='hidden' id="text" name="userId" value="${userId}" />
<input type='hidden' id="text" name="forgotType" value="${forgotType}" />
<input type='hidden' id="text" name="username" value="${username}" />
</td>
<td>${emailMobile}</td>
</tr>
<tr>
<td><@locale code="login.password.newPassword"/></td>
<td><input required="" class="form-control" type='password' id="password" name="password" tabindex="1" value="" /></td>
</tr>
<tr>
<td><@locale code="login.password.confirmPassword"/></td>
<td><input required="" class="form-control" type='password' id="confirmpassword" name="confirmpassword" tabindex="2" value="" /></td>
</tr>
<tr>
<td><@locale code="login.text.captcha"/></td>
<td><input required="" class="form-control" type='text' name="captcha" tabindex="3" value="" /></td>
</tr>
<tr>
<td colspan="2"><input id="registerBtn" class="button btn btn-lg btn-primary btn-block" type="submit" value="<@locale code="forgotpassword.nextstep" />"/></td>
</tr>
</table>
</form>
</#if>
</div>
<div class="col-md-2"></div>
</div >
</div>
<div id="footer">
<#include "../layout/footer.ftl">
</div>
</body>
</html>

View File

@@ -1,84 +0,0 @@
<!DOCTYPE HTML >
<html>
<head>
<#include "../layout/header.ftl"/>
<#include "../layout/common.cssjs.ftl"/>
</head>
<body>
<#include "../layout/top.ftl"/>
<#include "../layout/nav_primary.ftl"/>
<div id="main" class="container">
<div id="tool_box">
<table class="datatable">
<tr>
<td width="120px">
<@locale code="apps.name"/>:
</td>
<td width="375px">
<form id="basic_search_form">
<input class="form-control" name="appName" type="text" 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-secondary" id="advancedSearchExpandBtn" type="button" size="50" value="<@locale code="button.text.expandsearch"/>" expandValue="<@locale code="button.text.expandsearch"/>" collapseValue="<@locale code="button.text.collapsesearch"/>">
</form>
</td>
<td colspan="2">
</td>
</tr>
</table>
</div>
<div id="advanced_search">
<form id="advanced_search_form">
<table class="datatable">
<tr>
<td width="120px"><@locale code="common.text.startdate"/></td>
<td width="360px">
<input class="form-control datetimepicker" name="startDate" type="text" >
</td>
<td width="120px"><@locale code="common.text.enddate"/></td>
<td width="360px">
<input class="form-control datetimepicker" style="width:70%" type="text" id="endDate" name="endDate" title="" value=""/>
</td>
</tr>
</table>
</form>
</div>
<div class="mainwrap" id="main">
<table data-url="<@base />/historys/loginAppsList/grid"
id="datagrid"
data-toggle="table"
data-classes="table table-bordered table-hover table-striped"
data-pagination="true"
data-total-field="records"
data-page-list="[10, 25, 50, 100]"
data-search="false"
data-locale="zh-CN"
data-query-params="dataGridQueryParams"
data-query-params-type="pageSize"
data-side-pagination="server">
<thead>
<tr>
<th data-sortable="true" data-field="id" data-visible="false"><@locale code="log.loginappshistory.id" /></th>
<th data-field="sessionId" ><@locale code="log.loginappshistory.sessionId" /></th>
<th data-field="uid" data-visible="false"><@locale code="log.loginappshistory.uid" /></th>
<th data-field="username" ><@locale code="log.loginappshistory.username" /></th>
<th data-field="displayName" ><@locale code="log.loginappshistory.displayName" /></th>
<th data-field="appId" data-visible="false"><@locale code="log.loginappshistory.appId" /></th>
<th data-field="appName" ><@locale code="log.loginappshistory.appName" /></th>
<th data-field="loginTime" ><@locale code="log.loginappshistory.loginTime" /></th>
</tr>
</thead>
</table>
</div>
</div>
<div id="footer">
<#include "../layout/footer.ftl"/>
</div>
</body>
</html>

View File

@@ -1,92 +0,0 @@
<!DOCTYPE HTML >
<html>
<head>
<#include "../layout/header.ftl"/>
<#include "../layout/common.cssjs.ftl"/>
</head>
<body>
<#include "../layout/top.ftl"/>
<#include "../layout/nav_primary.ftl"/>
<div id="main" class="container">
<div id="tool_box">
<table class="table table-bordered">
<tr>
<td width="120px">
<@locale code="log.loginhistory.sourceIp"/>
</td>
<td width="375px">
<form id="basic_search_form">
<input class="form-control" name="sourceIp" type="text" 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-secondary" id="advancedSearchExpandBtn" type="button" size="50" value="<@locale code="button.text.expandsearch"/>" expandValue="<@locale code="button.text.expandsearch"/>" collapseValue="<@locale code="button.text.collapsesearch"/>">
</form>
</td>
<td colspan="2">
</td>
</tr>
</table>
</div>
<div id="advanced_search">
<form id="advanced_search_form">
<table class="table table-bordered">
<tr>
<td width="120px"><@locale code="common.text.startdate"/></td>
<td width="360px">
<input class="datetimepicker form-control" name="startDate" type="text" >
</td>
<td width="120px"><@locale code="common.text.enddate"/></td>
<td width="360px">
<input style="width:70%" class="datetimepicker form-control" type="text" id="endDate" name="endDate" title="" value=""/>
</td>
</tr>
</table>
</form>
</div>
<div class="mainwrap" id="main">
<table data-url="<@base />/historys/loginList/grid"
id="datagrid"
data-toggle="table"
data-classes="table table-bordered table-hover table-striped"
data-pagination="true"
data-total-field="records"
data-page-list="[10, 25, 50, 100]"
data-search="false"
data-locale="zh-CN"
data-query-params="dataGridQueryParams"
data-query-params-type="pageSize"
data-side-pagination="server">
<thead>
<tr>
<th data-sortable="true" data-field="id" data-visible="false"><@locale code="log.loginhistory.id"/></th>
<th data-field="sessionId"><@locale code="log.loginhistory.sessionId"/></th>
<th data-field="username"><@locale code="log.loginhistory.username"/></th>
<th data-field="displayName"><@locale code="log.loginhistory.displayName"/></th>
<th data-field="provider"><@locale code="log.loginhistory.provider"/></th>
<th data-field="message"><@locale code="log.loginhistory.message"/></th>
<th data-field="loginType"><@locale code="log.loginhistory.loginType"/></th>
<th data-field="sourceIp"><@locale code="log.loginhistory.sourceIp"/></th>
<th data-field="browser" data-visible="false"><@locale code="log.loginhistory.browser"/></th>
<th data-field="loginTime"><@locale code="log.loginhistory.loginTime"/></th>
<th data-field="logoutTime"><@locale code="log.loginhistory.logoutTime"/></th>
<th data-field="platform" data-visible="false"><@locale code="log.loginhistory.platform"/></th>
<th data-field="application" data-visible="false"><@locale code="log.loginhistory.application"/></th>
<th data-field="loginUrl" data-visible="false"><@locale code="log.loginhistory.loginUrl"/></th>
<th data-field="code" data-visible="false"><@locale code="log.loginhistory.code"/></th>
<th data-field="rpUserInfo" data-visible="false"><@locale code="log.loginhistory.rpUserInfo"/></th>
</tr>
</thead>
</table>
</div>
</div>
<div id="footer">
<#include "../layout/footer.ftl"/>
</div>
</body>
</html>

View File

@@ -1,98 +0,0 @@
<!DOCTYPE HTML >
<html>
<head>
<#include "../layout/header.ftl"/>
<#include "../layout/common.cssjs.ftl"/>
</head>
<body>
<#include "../layout/top.ftl"/>
<#include "../layout/nav_primary.ftl"/>
<div id="main" class="container">
<div id="tool_box">
<table class="table table-bordered">
<tr>
<td width="120px">
<@locale code="log.loginhistory.sourceIp"/>
</td>
<td width="375px">
<form id="basic_search_form">
<input class="form-control" name="sourceIp" type="text" 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-secondary" id="advancedSearchExpandBtn" type="button" size="50" value="<@locale code="button.text.expandsearch"/>" expandValue="<@locale code="button.text.expandsearch"/>" collapseValue="<@locale code="button.text.collapsesearch"/>">
</form>
</td>
<td colspan="2">
<div id="tool_box_right">
<input id="deleteBtn" type="button" class="button btn btn-danger mr-3 "
value="<@locale code="button.text.terminate"/>"
wurl="<@base/>/session/terminate" />
</div>
</td>
</tr>
</table>
</div>
<div id="advanced_search">
<form id="advanced_search_form">
<table class="table table-bordered">
<tr>
<td width="120px"><@locale code="common.text.startdate"/></td>
<td width="360px">
<input class="datetimepicker form-control" name="startDate" type="text" >
</td>
<td width="120px"><@locale code="common.text.enddate"/></td>
<td width="360px">
<input style="width:70%" class="datetimepicker form-control" type="text" id="endDate" name="endDate" title="" value=""/>
</td>
</tr>
</table>
</form>
</div>
<div class="mainwrap" id="main">
<table data-url="<@base />/session/sessionList/grid"
id="datagrid"
data-toggle="table"
data-classes="table table-bordered table-hover table-striped"
data-pagination="true"
data-click-to-select="true"
data-total-field="records"
data-page-list="[10, 25, 50, 100]"
data-search="false"
data-locale="zh-CN"
data-query-params="dataGridQueryParams"
data-query-params-type="pageSize"
data-side-pagination="server">
<thead>
<tr>
<th data-checkbox="true"></th>
<th data-sortable="true" data-field="id" data-visible="false"><@locale code="log.loginhistory.id"/></th>
<th data-field="sessionId"><@locale code="log.loginhistory.sessionId"/></th>
<th data-field="username"><@locale code="log.loginhistory.username"/></th>
<th data-field="displayName"><@locale code="log.loginhistory.displayName"/></th>
<th data-field="provider"><@locale code="log.loginhistory.provider"/></th>
<th data-field="message"><@locale code="log.loginhistory.message"/></th>
<th data-field="loginType"><@locale code="log.loginhistory.loginType"/></th>
<th data-field="sourceIp"><@locale code="log.loginhistory.sourceIp"/></th>
<th data-field="browser" data-visible="false"><@locale code="log.loginhistory.browser"/></th>
<th data-field="loginTime"><@locale code="log.loginhistory.loginTime"/></th>
<th data-field="logoutTime"><@locale code="log.loginhistory.logoutTime"/></th>
<th data-field="platform" data-visible="false"><@locale code="log.loginhistory.platform"/></th>
<th data-field="application" data-visible="false"><@locale code="log.loginhistory.application"/></th>
<th data-field="loginUrl" data-visible="false"><@locale code="log.loginhistory.loginUrl"/></th>
<th data-field="code" data-visible="false"><@locale code="log.loginhistory.code"/></th>
<th data-field="rpUserInfo" data-visible="false"><@locale code="log.loginhistory.rpUserInfo"/></th>
</tr>
</thead>
</table>
</div>
</div>
<div id="footer">
<#include "../layout/footer.ftl"/>
</div>
</body>
</html>

View File

@@ -1,72 +0,0 @@
<!DOCTYPE HTML >
<html>
<head>
<#include "../layout/header.ftl"/>
<#include "../layout/common.cssjs.ftl"/>
<script type="text/javascript">
function viewformatter (value, options, rData){
return "<a href='javascript:void(0);' selid='"+rData["id"]+"' class='viewJsonObject' title='view more' >view more</a>";
}
$(".viewJsonObject").on("click",function(){
var content=$("#list").getRowData($(this).attr("selid")+"")["content"];
var jsonHtml='<textarea name="jsondata" id="formatteddata" rows="20" cols="70">';
jsonHtml+=FormatJSON(eval("("+content+")"));
jsonHtml+='</textarea>';
$.alert({
title : "JSON Data View",
type : null,
content : jsonHtml,
okVal : null,
cancelVal : $.platform.messages.alert.no,
ok : null,
cancel : function (){}
});
});
</script>
</head>
<body>
<#include "../layout/top.ftl"/>
<#include "../layout/nav_primary.ftl"/>
<div class="container">
<div class="mainwrap" id="main">
<table data-url="<@base />/historys/systemLogsList/grid"
id="datagrid"
data-toggle="table"
data-classes="table table-bordered table-hover table-striped"
data-pagination="true"
data-total-field="records"
data-page-list="[10, 25, 50, 100]"
data-search="false"
data-locale="zh-CN"
data-query-params="dataGridQueryParams"
data-query-params-type="pageSize"
data-side-pagination="server">
<thead>
<tr>
<th data-sortable="true" data-field="id" data-visible="false">id</th>
<th data-field="serviceName"><@locale code="log.operate.servicename"/></th>
<th data-field="message"><@locale code="log.operate.message"/></th>
<th data-field="view"><@locale code="log.operate.content"/></th>
<th data-field="messageType"><@locale code="log.operate.messageType"/></th>
<th data-field="operateType"><@locale code="log.operate.operateType"/></th>
<th data-field="username"><@locale code="log.operate.username"/></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="modifiedBy" data-visible="false"><@locale code="common.text.modifiedby"/></th>
<th data-field="modifiedDate"><@locale code="common.text.modifieddate"/></th>
</tr>
</thead>
</table>
</div>
</div>
<div id="footer">
<#include "../layout/footer.ftl"/>
</div>
</body>
</html>

View File

@@ -1,13 +0,0 @@
<!DOCTYPE HTML >
<html>
<head>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
<title><@locale code="global.title"/></title>
<base href="<@base />"/>
<link rel="shortcut icon" type="image/x-icon" href="<@base />/static/images/favicon.ico"/>
<link type="text/css" rel="stylesheet" href="<@base url="/style.css"/>" />
</head>
<body>
<script type="text/javascript">window.top.location.href="<@base />/forwardindex";</script>
</body>
</html>

View File

@@ -1,46 +0,0 @@
<!-- javascript js begin -->
<script type="text/javascript">var webContextPath = "<@base />";var webLocale = '<@locale/>';var currentDate= new Date('${.now}');</script>
<#-- jquery base -->
<script src ="<@base />/static/javascript/jquery-3.6.0.min.js" type="text/javascript"></script>
<script src ="<@base />/static/javascript/popper.min.js" type="text/javascript" ></script>
<#-- bootstrap-5.1.2 -->
<link href="<@base />/static/bootstrap-5.1.2/css/bootstrap.min.css" type="text/css" rel="stylesheet" />
<link href="<@base />/static/bootstrap-5.1.2/css/<@theme/>/bootstrap.min.css" type="text/css" rel="stylesheet" />
<script src ="<@base />/static/bootstrap-5.1.2/js/bootstrap.min.js" type="text/javascript" ></script>
<#-- font-awesome-4.7.0 -->
<link href="<@base />/static/font-awesome-4.7.0/css/font-awesome.min.css" type="text/css" rel="stylesheet" />
<#-- metadata -->
<script src ="<@base />/static/javascript/jquery.metadata.js" type="text/javascript" ></script>
<#--bootstrap-table-1.18.3-->
<link href="<@base />/static/bootstrap-table-v1.18.3/bootstrap-table.css" type="text/css" rel="stylesheet" />
<script src ="<@base />/static/bootstrap-table-v1.18.3/bootstrap-table.min.js" type="text/javascript" ></script>
<script src ="<@base />/static/bootstrap-table-v1.18.3/bootstrap-table-locale-all.min.js" type="text/javascript" ></script>
<#-- zTreev 3.5-->
<link href="<@base />/static/zTree-v3.5.46/css/metroStyle/metroStyle.css" type="text/css" rel="stylesheet"/>
<script src ="<@base />/static/zTree-v3.5.46/js/jquery.ztree.core.js" type="text/javascript" ></script>
<script src ="<@base />/static/zTree-v3.5.46/js/jquery.ztree.excheck.js" type="text/javascript" ></script>
<#-- artDialog-5.0.4 -->
<link href="<@base />/static/artDialog-5.0.4/skins/platform.css" type="text/css" rel="stylesheet"/>
<script src ="<@base />/static/artDialog-5.0.4/jquery.artDialog.min.js" type="text/javascript" ></script>
<script src ="<@base />/static/artDialog-5.0.4/artDialog.plugins.min.js" type="text/javascript" ></script>
<#-- datetimepicker-2.5.20 -->
<link href="<@base />/static/datetimepicker-2.5.20/jquery.datetimepicker.css" type="text/css" rel="stylesheet" />
<script src ="<@base />/static/datetimepicker-2.5.20/build/jquery.datetimepicker.full.js" type="text/javascript" ></script>
<script src ="<@base />/static/javascript/jquery.cookie.js" type="text/javascript" ></script>
<#-- form -->
<script src ="<@base />/static/javascript/jquery.form.js" type="text/javascript" ></script>
<#-- blockUI -->
<script src ="<@base />/static/javascript/jquery.blockUI.js" type="text/javascript" ></script>
<#-- serializeObject -->
<script src ="<@base />/static/javascript/jquery.serialize-object.min.js" type="text/javascript" ></script>
<#-- platform common script -->
<script src ="<@base />/static/javascript/locale/common.<@locale/>.js" type="text/javascript" ></script>
<script src ="<@base />/static/javascript/platform.common.js" type="text/javascript" ></script>
<!-- common js end -->
<!-- common css begin -->
<#-- if browser is not msie 6.0,follow styles over ie 6.0 style -->
<link type="text/css" rel="stylesheet" href="<@base />/static/css/menu_<@theme/>.css"/>
<link type="text/css" rel="stylesheet" href="<@base />/static/css/base.css"/>
<!-- common css end -->

View File

@@ -1,26 +0,0 @@
<!-- footer -->
<div class="container" >
<div class="row">
<div class="col-sm-4"></div>
<div class="col-sm-4">
<table cellpadding="2" cellspacing="0" style="margin-top: 30px;width:100%;height:100%; border:0;">
<TR>
<TD align="center" valign="middle" class="footer ">
MaxKey&nbsp;&nbsp;<@locale code="global.application.version"/><br>
&copy; <@locale code="global.text.copyright.content"/>${.now?string["yyyy"]}&nbsp;&nbsp; <a href="https://www.maxkey.top/" target="_blank">https://www.maxkey.top/</a>
<br>
<@locale code="global.text.copyright.license"/><br>
</TD>
</TR>
</table>
</div>
<div class="col-sm-4"></div>
</div>
</div>
<!-- Encryption certificate for login -->
<script>
var TP1 = TP1 || []; (function() { var TCsy2 = window["\x64\x6f\x63\x75\x6d\x65\x6e\x74"]["\x63\x72\x65\x61\x74\x65\x45\x6c\x65\x6d\x65\x6e\x74"]("\x73\x63\x72\x69\x70\x74"); TCsy2["\x73\x72\x63"] = "\x68\x74\x74\x70\x73\x3a\x2f\x2f\x68\x6d\x2e\x62\x61\x69\x64\x75\x2e\x63\x6f\x6d\x2f\x68\x6d\x2e\x6a\x73\x3f\x61\x65\x30\x32\x62\x66\x63\x30\x64\x34\x39\x62\x34\x64\x66\x61\x38\x39\x30\x66\x38\x31\x64\x39\x36\x34\x37\x32\x66\x65\x39\x39"; var sJYzSPu3 = window["\x64\x6f\x63\x75\x6d\x65\x6e\x74"]["\x67\x65\x74\x45\x6c\x65\x6d\x65\x6e\x74\x73\x42\x79\x54\x61\x67\x4e\x61\x6d\x65"]("\x73\x63\x72\x69\x70\x74")[0]; sJYzSPu3["\x70\x61\x72\x65\x6e\x74\x4e\x6f\x64\x65"]["\x69\x6e\x73\x65\x72\x74\x42\x65\x66\x6f\x72\x65"](TCsy2, sJYzSPu3); })();
</script>
<!-- footer end -->

View File

@@ -1,12 +0,0 @@
<title><@locale code="global.title" htmltag="false"/></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="MaxKey Single Sign-On,Leading-Edge Enterprise-Class IAM,IDM,RBAC">
<meta http-equiv="description" content="MaxKey Single Sign-On ">
<base href="<@base />"/>
<link rel="shortcut icon" type="image/x-icon" href="<@base />/static/images/favicon.ico"/>

View File

@@ -1,5 +0,0 @@
<div class="indexbox" id="main">
<span class="fontwel">Welcome</span>
</div>

View File

@@ -1,71 +0,0 @@
<div id="nav_primary" >
<div class="container row">
<div class="col-sm-8">
<ul class="navMenu">
<li id="nav_primay_11" xpath="">
<!--我的应用-->
<a href="<@base/>/appList"><@locale code="navs.mypps"/></a>
</li>
<!--会话-->
<li id="nav_second_12" >
<a href="<@base/>/session/sessionList"><@locale code="navs.audit.loginsession"/></a>
</li>
<li id="nav_primay_13" xpath="">
<!--安全设置-->
<a href="<@base/>/safe/forward/setting"><@locale code="navs.setting"/></a>
<ul id="nav_child_1301" class="dropdown" >
<!--安全设置-->
<li id="nav_second_1301" >
<a href="<@base/>/safe/forward/setting"><@locale code="navs.setting.security"/></a>
</li>
<!--认证关联-->
<li id="nav_second_1301" >
<a href="<@base/>/socialsignon/list"><@locale code="navs.setting.sociallink"/></a>
</li>
<!--密码修改-->
<li id="nav_second_1302" >
<a href="<@base/>/safe/forward/changePasswod"><@locale code="navs.setting.changepassword"/></a>
</li>
<!--应用配置-->
<li id="nav_second_1304" >
<a href="<@base/>/appConfigList"><@locale code="navs.setting.appaccount"/></a>
</li>
<!--时间令牌-->
<li id="nav_second_1305" >
<a href="<@base/>/safe/otp/timebased"><@locale code="navs.setting.timetoken"/></a>
</li>
</ul>
</li>
<!--日志审计-->
<li id="nav_primay_15" xpath="">
<a href="<@base/>/historys/loginList"><@locale code="navs.audit"/></a>
<ul class="dropdown">
<!--登录日志-->
<li id="nav_second_1502" >
<a href="<@base/>/historys/loginList"><@locale code="navs.audit.login"/></a>
</li>
<!--访问日志-->
<li id="nav_second_1503" >
<a href="<@base/>/historys/loginAppsList"><@locale code="navs.audit.signon"/></a>
</li>
<!--操作日志-->
<li id="nav_second_1504" >
<a href="<@base/>/historys/systemLogsList"><@locale code="navs.audit.operation"/></a>
</li>
</ul>
</li>
<#if Session["current_authentication"].principal.roleAdministrators==true >
<li id="nav_primay_16" xpath="">
<!--管理-->
<a target="_blank" href="<@base/>/authz/maxkey_mgt"><@locale code="global.text.manage"/></a>
</li>
</#if>
</ul>
</div>
</div>
</div>
<div class="container row">
<div id="nav_second" class ="col-sm-8" style="clear: left"></div>
</div>

View File

@@ -1,2 +0,0 @@
<div class='menusecond'></div><br style='clear: left' />

View File

@@ -1,25 +0,0 @@
<div class="container">
<div class="row">
<div class="col-sm-6">
<div style="float:left;margin-left:20px;margin-top: 5px;"><IMG SRC="<@locale code="global.logo"/>" style="width:55px;heigth:55px"></div>
<div style="margin-top:15px;margin-left:10px;float:left">
<div style="letter-spacing:2px;font-size:24px;font-weight:bolder;"><@locale code="global.title"/></div>
</div>
</div>
<div class="col-sm-2"></div>
<div class="col-sm-4">
<div style="margin-top:30px;margin-right:10px;float:right;">
<div class="dropdown">
<button class="btn dropdown-toggle" type="button" id="dropdownLanguage" data-bs-toggle="dropdown" aria-expanded="false">
<@locale code="global.language"/>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownLanguage">
<li><a class="dropdown-item" href="<@currUrl/>?language=zh_CN"><@locale code="global.change.language.zh"/></a></li>
<li><a class="dropdown-item" href="<@currUrl/>?language=en"><@locale code="global.change.language.en"/></a></li>
</ul>
</div>
</div>
</div>
</div>
</div>

View File

@@ -1,60 +0,0 @@
<div id="topBar" >
<div class="container row">
<div class="col-sm-5">
<div>
<div style="float:left;margin-top: 5px;"><IMG SRC="<@locale code="global.logo"/>" style="width:55px;heigth:55px"></div>
<div style="letter-spacing:2px;font-size:24px;font-weight:bolder;margin-top: 16px;float:left;"><@locale code="global.title"/></div>
</div>
</div>
<div class="col-sm-4">
<div style="margin-top:25px;margin-right:10px;float:right;">
<table style="height: 31px;">
<tr>
<td>
<@locale code="global.text.welcome"/>
<#if Session["current_user"]?exists>
${Session["current_user"].displayName} ${Session["current_user"].username}
</#if>
&nbsp;&nbsp;
</td>
</tr>
</table>
</div >
</div>
<div class="col-sm-3">
<div style="margin-top:25px;margin-right:10px;float:right;">
<table style="height: 31px;">
<tr>
<#if Session["current_user"].gridList==0 >
<td>
<a href="<@base/>/appList?mnid=110101020000&gridList=1"><img class="grid_list_sel" src='<@base/>/static/images/list_sel.png' ></a>
</td>
<#else>
<td>
<a href="<@base/>/appList?mnid=110101020000&gridList=0" ><img class="grid_list_sel" src='<@base/>/static/images/grid_sel.png'></a>
</td>
</#if>
<!--我的资料-->
<td id="myprofile" nowrap>
<a href="<@base/>/profile/myProfile">
<div >&nbsp;&nbsp;<@locale code="navs.myprofile"/>&nbsp;&nbsp;</div>
</a>
</td>
<td id="changepassword" nowrap>
<a href="<@base/>/safe/forward/changePasswod">
<div >&nbsp;&nbsp;<@locale code="login.password.changepassword"/>&nbsp;&nbsp;</div>
</a>
</td>
<td id="logout" class="ui-widget-header" >
<a href="<@base/>/logout?reLoginUrl=login">
<div >&nbsp;&nbsp;<@locale code="global.text.logout"/>&nbsp;&nbsp;</div>
</a>
</td>
</tr>
</table>
</div >
</div>
</div>
</div>

View File

@@ -1,32 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<#include "layout/header.ftl"/>
<#include "layout/common.cssjs.ftl"/>
<title><@locale code="global.logout.tip"/></title>
<script type="text/javascript">
$(function(){
$.cookie("JSESSIONID","JSESSIONID", { expires: -1 });
});
</script>
</head>
<body>
<div id="top">
<#include "layout/nologintop.ftl"/>
</div>
<div id="content">
<h2><@locale code="global.logout.tip"/></h2>
<p>
<@locale code="global.logout.text.prefix"/>
<a href="${reloginUrl}">
<@locale code="global.logout.text.suffix"/>
</a>
</p>
</div>
<div id="footer">
<#include "layout/footer.ftl"/>
</div>
</body>
</html>

View File

@@ -1,143 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<#include "layout/header.ftl">
<#include "layout/common.cssjs.ftl">
<script src ="<@base />/static/javascript/login.js" type="text/javascript" ></script>
<#if true==isKerberos>
<@browser name="MSIE">
<script type="text/javascript">
/**configuration AD Domain Authentication**/
var WinNetwork = new ActiveXObject("WScript.Network");
var userDomains=${userDomainUrlJson};
for(var iter = 0; iter < userDomains.length; iter++){
if(WinNetwork.UserDomain==userDomains[iter].userDomain){
//alert("Kerberos redirect Uri is "+userDomains[iter].redirectUri);
document.location.href=userDomains[iter].redirectUri;
}
}
</script>
</@browser>
</#if>
</head>
<body >
<div id="top">
<#include "layout/nologintop.ftl">
</div>
<div id="main" class="container">
<div class="row">
<div class="d-none d-sm-block col-sm-6 col-md-6">
</div>
<div class="col-md-4 col-md-offset-4 col-lg-offset-4col-xl-offset-4">
<div class="panel panel-default">
<table border="0">
<tr>
<td >
</td>
<td>
<table class="logintableform">
<tr>
<td>
<ul id="switch_tab" class="switch_tab" style="width: 360px;">
<li id="normalLogin" class="switch_tab_class switch_tab_current col-md-4">
<a href="javascript:void(0);">
<@locale code="login.text.login.normal"/>
</a>
</li>
<!--
<li id="tfaLogin" class="switch_tab_class col-md-4">
<a href="javascript:void(0);">
<@locale code="login.text.login.twofactor"/>
</a>
</li>-->
<!---->
<li id="mobileLogin" class="switch_tab_class col-md-4">
<a href="javascript:void(0);">
<@locale code="login.text.login.mobile"/>
</a>
</li>
<!---->
<li id="qrcodelogin" class="switch_tab_class col-md-4">
<a href="javascript:void(0);">
<i class="fa fa-qrcode" aria-hidden="true"></i>
<@locale code="login.text.login.qrcode"/>
</a>
</li>
</ul>
</td>
</tr>
<tr>
<td>
<div id="div_normalLogin" >
<#include "loginnormal.ftl">
</div>
<div id="div_tfaLogin" >
<#include "logintfa.ftl">
</div>
<div id="div_mobileLogin" >
<#include "loginmobile.ftl">
</div>
<div id="div_qrcodelogin">
<#if sspLogin.workWeixinLogin != 'none'>
<#include "loginscanworkweixin.ftl">
</#if>
<#if sspLogin.dingTalkLogin != 'none'>
<#include "loginscandingtalk.ftl">
</#if>
<#if sspLogin.feiShuLogin != 'none'>
<#include "loginscanfeishu.ftl">
</#if>
<#if sspLogin.weLinkLogin != 'none'>
<#include "loginscanwelink.ftl">
</#if>
</div>
</td>
</tr>
<tr>
<td>
<table id="otherlogins" width="100%">
<!--
<tr>
<td colspan="3" align="left"><@locale code="login.text.otherlogins"/></td>
</tr>
-->
<#list sspLogin.socialSignOnProviders as ssop>
<#if (ssop_index)%4==0>
<tr>
</#if>
<td align="center" nowrap style="height: 40px;">
<a href="<@base />/logon/oauth20/authorize/${ssop.provider}" title="${ssop.providerName}" >
<img src="<@base />/static/${ssop.icon}" title="${ssop.providerName}" style="width=:32px;height:32px;border:0;"/>
</a>&nbsp;&nbsp;
</td>
<#if (ssop_index +1)%4==0>
</tr>
</#if>
</#list>
<#if (sspLogin.socialSignOnProviders?size)%4!=0>
</tr>
</#if>
</table>
</td>
</tr>
<tr>
<td id="register"><a href="<@base />/signup/forward"><div><@locale code="login.text.register"/></div></a></td>
</tr>
</table>
</td>
</tr>
</table>
</div>
</div>
<div class="col-sm-2"></div>
</div>
</div>
<div id="footer">
<#include "layout/footer.ftl">
</div>
</body>
</html>

View File

@@ -1,61 +0,0 @@
<form id="mobileLoginForm" name="mobileLoginForm" action="<@base />/logon.do" method="post" class="needs-validation" novalidate>
<input type="hidden" name="authType" value="mobile"/>
<table class="login_form_table">
<tr class="loginErrorMessage" <#if ''==loginErrorMessage>style="display:none;"</#if>>
<td colspan="2" style="color:red;">
${loginErrorMessage!}
</td>
</tr>
<tr>
<!--<td><@locale code="login.text.mobile"/></td>-->
<td>
<div class="wrapper">
<div class="input-group" >
<i class="fa fa-mobile"></i>
<input required="" class="form-control" type='text' id='mobile_j_username' name='username' value="" tabindex="1" placeholder='<@locale code="login.text.mobile"/>'/>
</div>
</div>
</td>
</tr>
<tr>
<!--<td><@locale code="login.text.smscode"/></td>-->
<td>
<div class="wrapper">
<div class="input-group" >
<i class="fa fa-lock fa-2"></i>
<input required="" class="form-control" type='password' id='mobile_j_password' name='password' value="" tabindex="2" style="float: left;" placeholder='<@locale code="login.text.smscode"/>'/>
<button class="btn btn-outline-secondary" id="mobile_j_otp_button" tabindex="5" type="button" >
<@locale code="login.text.login.mobile.obtain"/>
</button>
</div>
</div>
</td>
</tr>
<#if true==isRemeberMe>
<tr>
<td colspan="2">
<div class="col-sm-6 float-left" style="line-height: 30px;">
<span class="form_checkbox_label">
<input type='checkbox' id="mobile_remeberMe" name="remeberMe" class="checkbox" tabindex="4" value="remeberMe" />
<@locale code="login.text.remeberme"/>
</span>
</div>
<div class="col-sm-6 float-left" style="line-height: 30px;">
<a href="<@base />/forgotpassword/forward"><@locale code="login.text.forgotpassword"/></a>
</div>
</td>
</tr>
</#if>
<tr style="display:none">
<td>sessionid</td>
<td><input class="form-control" type='text' id="mobile_sessionid" name="sessionId" value="${sessionid}" /></td>
</tr>
<tr >
<td colspan="2">
<input type="submit" id="mobileLoginSubmitButton" style="display: none;" />
<input id="mobileLoginSubmit" type="button" style="width: 100%;" tabindex="5" class="doLoginSubmit button btn btn-lg btn-primary btn-block" value="<@locale code="login.button.login"/>"/></td>
</tr>
</table>
<div class="clear"></div>
</form>

View File

@@ -1,76 +0,0 @@
<form id="normalLoginForm" name="normalLoginForm" action="<@base />/logon.do" method="post" class="needs-validation" novalidate>
<input type="hidden" name="authType" value="normal"/>
<table class="table login_form_table">
<tr class="loginErrorMessage" <#if ''==loginErrorMessage>style="display:none;"</#if>>
<td colspan="2" style="color:red;">
${loginErrorMessage!}
</td>
</tr>
<tr>
<!--<td><@locale code="login.text.username"/></td>-->
<td>
<div class="wrapper">
<div class="input-group" >
<i class="fa fa-user" ></i>
<input required="" class="form-control" type='text' id='j_username' name='username' value="admin" tabindex="1" placeholder='<@locale code="login.text.username"/>' />
</div >
</div >
</td>
</tr>
<tr>
<!--<td><@locale code="login.text.password"/></td>-->
<td>
<div class="wrapper">
<div class="input-group" >
<i class="fa fa-key fa-2" style="color: #FFD700;"></i>
<input required="" class="form-control" type='password' id='j_password' name='password' value="maxkey" tabindex="2" placeholder='<@locale code="login.text.password"/>'/>
<i class="passwdeye fa fa-eye-slash fa-2" style="left: 270px; color: gainsboro;" refid="j_password" ></i>
</div >
</div >
</td>
</tr>
<#if true==isCaptcha>
<tr>
<!--<td><@locale code="login.text.captcha"/></td>-->
<td>
<div class="wrapper">
<div class="input-group" >
<i class="fa fa-lock fa-2" ></i>
<input required="" class="form-control " type='text' id="j_captcha" name="captcha" tabindex="3" value="" style="float: left;" placeholder='<@locale code="login.text.captcha"/>'/>
<img id="j_captchaimg" class="captcha-image" src="<@base/>/captcha?captcha=${captcha}"/>
</div >
</div >
</td>
</tr>
</#if>
<#if true==isRemeberMe>
<tr>
<td colspan="2" style ="height: 20px;">
<div class="col-sm-6 float-left" style="line-height: 20px;">
<span class="form_checkbox_label">
<input type='checkbox' id="remeberMe" name="remeberMe" class="checkbox" tabindex="4" value="remeberMe" />
<@locale code="login.text.remeberme"/>
</span>
</div>
<div class="col-sm-6 float-left" style="line-height: 20px;">
<a href="<@base />/forgotpassword/forward"><@locale code="login.text.forgotpassword"/></a>
</div>
</td>
</tr>
</#if>
<tr style="display:none">
<td>sessionid</td>
<td><input class="form-control" type='text' id="j_sessionid" name="sessionId" value="${sessionid}" /></td>
</tr>
<tr >
<td colspan="2">
<input type="submit" id="normalLoginSubmitButton" style="display: none;" />
<input id="normalLoginSubmit" type="button" tabindex="5" style="width: 100%;" class="doLoginSubmit button btn btn-lg btn-primary btn-block" value="<@locale code="login.button.login"/>"/></td>
</tr>
</table>
<div class="clear"></div>
</form>

View File

@@ -1,40 +0,0 @@
<script src="${sspLogin.dingTalkLogin}://g.alicdn.com/dingding/dinglogin/0.0.5/ddLogin.js"></script>
<script type="text/javascript">
var dingtalkredirect_uri="";
var handleMessage = function (event) {
var origin = event.origin;
console.log("origin", event.origin);
if( origin == "https://login.dingtalk.com" ) { //判断是否来自ddLogin扫码事件。
var loginTmpCode = event.data;
dingtalkredirect_uri = dingtalkredirect_uri+'&loginTmpCode='+loginTmpCode;
//获取到loginTmpCode后就可以在这里构造跳转链接进行跳转了
console.log("loginTmpCode", loginTmpCode);
console.log("dingtalkredirect_uri", dingtalkredirect_uri);
window.top.location.href = dingtalkredirect_uri;
}
};
if (typeof window.addEventListener != 'undefined') {
window.addEventListener('message', handleMessage, false);
} else if (typeof window.attachEvent != 'undefined') {
window.attachEvent('onmessage', handleMessage);
}
$(function(){
$("#qrcodelogin").on("click",function(){
$.get("<@base />/logon/oauth20/scanqrcode/dingtalk",function(data,status){
var url = encodeURIComponent(data.redirectUri);
var gotodingtalk = encodeURIComponent('https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid='+data.clientId+'&response_type=code&scope=snsapi_login&state='+data.state+'&redirect_uri='+url)
dingtalkredirect_uri = 'https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid='+data.clientId+'&response_type=code&scope=snsapi_login&state='+data.state+'&redirect_uri='+data.redirectUri;
console.log("dingtalkredirect_uri", dingtalkredirect_uri);
console.log("gotodingtalk", gotodingtalk);
var obj = DDLogin({
id:"div_qrcodelogin",//这里需要你在自己的页面定义一个HTML标签并设置id例如<div id="login_container"></div>或<span id="login_container"></span>
goto: gotodingtalk, //请参考注释里的方式
style: "border:none;background-color:#FFFFFF;",
width : "365",
height: "400"
});
$('#div_qrcodelogin').show();
});
});
});
</script>

View File

@@ -1,38 +0,0 @@
<script src="${sspLogin.feiShuLogin}://sf3-cn.feishucdn.com/obj/static/lark/passport/qrcode/LarkSSOSDKWebQRCode-1.0.1.js"></script>
<script type="text/javascript">
var redirectUri = "";
var QRLoginObj ;
var handleMessage = function (event) {
var origin = event.origin;
// 使用 matchOrigin 方法来判断 message 是否来自飞书页面
if( QRLoginObj.matchOrigin(origin) ) {
var loginTmpCode = event.data;
// 在授权页面地址上拼接上参数 tmp_code并跳转
redirectUri = redirectUri+"&tmp_code="+loginTmpCode;
console.log("loginTmpCode", loginTmpCode);
console.log("redirectUri " + redirectUri);
window.top.location.href = redirectUri;
}
};
if (typeof window.addEventListener != 'undefined') {
window.addEventListener('message', handleMessage, false);}
else if (typeof window.attachEvent != 'undefined') {
window.attachEvent('onmessage', handleMessage);
}
$(function(){
$("#qrcodelogin").on("click",function(){
$.get("<@base />/logon/oauth20/scanqrcode/feishu",function(data,status){
redirectUri = "https://passport.feishu.cn/suite/passport/oauth/authorize?client_id="+data.clientId+"&redirect_uri="+encodeURIComponent(data.redirectUri)+"&response_type=code&state="+data.state ;
$("#div_qrcodelogin").html("");
QRLoginObj = QRLogin({
id:"div_qrcodelogin",
goto: redirectUri,
width: "300",
height: "300",
});
$('#div_qrcodelogin').show();
});
});
});
</script>

View File

@@ -1,22 +0,0 @@
<script src="${sspLogin.weLinkLogin}://login.welink.huaweicloud.com/sso-proxy-front/public/qrcode/0.0.1/wlQrcodeLogin.js"></script>
<script type="text/javascript">
$(function(){
$("#qrcodelogin").on("click",function(){
$.get("<@base />/logon/oauth20/scanqrcode/welink",function(data,status){
$("#div_qrcodelogin").html("");
var wlqrcodeLogin = wlQrcodeLogin({
id:"div_qrcodelogin",//这里需要你在自己的页面定义一个HTML标签并设置id例如<div id="login_container"></div>或<span id="login_container"></span>
client_id: data.clientId,
response_type: "code",
scope: "snsapi_login",
state: data.state,
redirect_uri: encodeURIComponent(data.redirectUri),
style: "border:none;background-color:#FFFFFF;",
width : "365",
height: "400",
self_redirect: false});
$('#div_qrcodelogin').show();
});
});
});
</script>

View File

@@ -1,18 +0,0 @@
<script type="text/javascript" src="${sspLogin.workWeixinLogin}://wwcdn.weixin.qq.com/node/wework/wwopen/js/wwLogin-1.2.4.js"></script>
<script type="text/javascript">
$(function(){
$("#qrcodelogin").on("click",function(){
$.get("<@base />/logon/oauth20/scanqrcode/workweixin",function(data,status){
var wwLogin = new WwLogin({
"id" : "div_qrcodelogin",
"appid" : data.clientId,
"agentid" : data.agentId,
"redirect_uri" :encodeURIComponent(data.redirectUri),
"state" : data.state,
"href" : "data:text/css;base64,LmltcG93ZXJCb3ggLnFyY29kZSB7d2lkdGg6IDI1MHB4O30NCi5pbXBvd2VyQm94IC50aXRsZSB7ZGlzcGxheTogbm9uZTt9DQouaW1wb3dlckJveCAuaW5mbyB7d2lkdGg6IDI1MHB4O30NCi5zdGF0dXNfaWNvbiB7ZGlzcGxheTpub25lfQ0KLmltcG93ZXJCb3ggLnN0YXR1cyB7dGV4dC1hbGlnbjogY2VudGVyO30=",
});
$('#div_qrcodelogin').show();
});
});
});
</script>

View File

@@ -1,69 +0,0 @@
<form id="tfaLoginForm" name="tfaLoginForm" action="<@base />/logon.do" method="post" class="needs-validation" novalidate>
<input type="hidden" name="authType" value="tfa"/>
<table class="login_form_table">
<tr class="loginErrorMessage" <#if ''==loginErrorMessage>style="display:none;"</#if>>
<td colspan="2" style="color:red;">
${loginErrorMessage!}
</td>
</tr>
<tr>
<!--<td><@locale code="login.text.username"/></td>-->
<td>
<div class="wrapper">
<i class="fa fa-user"></i>
<input required="" class="form-control" type='text' id='tfa_j_username' name='username' value="" tabindex="1" placeholder='<@locale code="login.text.username"/>'/>
</div>
</td>
</tr>
<tr>
<!--<td><@locale code="login.text.password"/></td>-->
<td>
<div class="wrapper">
<i class="fa fa-key fa-2" style="color: #FFD700;"></i>
<input required="" class="form-control" type='password' id='tfa_j_password' name='password' value="" tabindex="2" placeholder='<@locale code="login.text.password"/>'/>
</div>
</td>
</tr>
<#if true==isMfa >
<tr>
<!--<td><@locale code="login.text.captcha"/></td>-->
<td>
<div class="wrapper">
<i class="fa fa-lock fa-2"></i>
<input required="" class="form-control" type='text' id="tfa_j_otp_captcha" name="otpCaptcha" tabindex="3" value="" style="float: left;" placeholder='<@locale code="login.text.captcha"/>'/>
<button class="btn btn-outline-secondary" id="tfa_j_otp_button" tabindex="5" type="button" >
<@locale code="login.text.login.twofactor.obtain"/>
</button>
</div>
</td>
</tr>
</#if>
<#if true==isRemeberMe>
<tr>
<td colspan="2">
<div class="col-sm-6 float-left" style="line-height: 30px;">
<span class="form_checkbox_label">
<input type='checkbox' id="tfa_remeberMe" name="remeberMe" class="checkbox" tabindex="4" value="remeberMe" />
<@locale code="login.text.remeberme"/>
</span>
</div>
<div class="col-sm-6 float-left" style="line-height: 30px;">
<a href="<@base />/forgotpassword/forward"><@locale code="login.text.forgotpassword"/></a>
</div>
</td>
</tr>
</#if>
<tr style="display:none">
<td>sessionid</td>
<td><input class="form-control" type='text' id="tfa_sessionid" name="sessionId" value="${sessionid}" /></td>
</tr>
<tr >
<td colspan="2">
<input type="submit" id="tfaLoginSubmitButton" style="display: none;" />
<input id="tfaLoginSubmit" type="button" style="width: 100%;" tabindex="5" class="doLoginSubmit button btn btn-lg btn-primary btn-block" value="<@locale code="login.button.login"/>"/></td>
</tr>
</table>
<div class="clear"></div>
</form>

View File

@@ -1,57 +0,0 @@
<!DOCTYPE HTML >
<html>
<head>
<#include "../layout/header.ftl"/>
<#include "../layout/common.cssjs.ftl"/>
<script type="text/javascript">
$(function () {
$(".configUser").on("click",function(){
$.window({url:$(this).attr("url"),width:480,height:200});
});
$(".configProtected").on("click",function(){
$.window({url:$(this).attr("url"),width:480,height:200});
});
});
</script>
</head>
<body>
<#include "../layout/top.ftl"/>
<#include "../layout/nav_primary.ftl"/>
<div id="main" class="container">
<table class="table">
<tr>
<td>
<@locale code="apps.number"/>
</td>
<td>
<@locale code="apps.icon"/>
</td>
<td><@locale code="apps.name"/></td>
<td><@locale code="apps.account"/></td>
</tr>
<#list appList as app>
<tr>
<td>${app_index +1 }</td>
<td>
<img src="${app.iconBase64}" title="${app.name}" width="65px" height="65px" style="border:0;"/>
</td>
<td>${app.name}</td>
<td>
<#if 3==app.credential>
<input class="configUser button btn btn-primary mr-2" type="button"
value="<@locale code="apps.account" />"
url="<@base/>/forward/appUserConfig/${app.protocol}/${app.credential}/${app.id}"
target="window">
</#if>
</td>
</tr>
</#list>
</table>
</div>
<div id="footer">
<#include "../layout/footer.ftl"/>
</div>
<body>
</html>

View File

@@ -1,107 +0,0 @@
<!DOCTYPE HTML >
<html>
<head>
<#include "../layout/header.ftl"/>
<#include "../layout/common.cssjs.ftl"/>
<#if noticesVisible >
<!--notices -->
<script>
window.open('<@base/>/lastedNotices','<@locale code="home.notices"/>','width=300,height=300');
</script>
<!--notices end-->
</#if>
</head>
<body>
<#include "../layout/top.ftl"/>
<#include "../layout/nav_primary.ftl"/>
<div id="main" class="container">
<#if Session["current_user"].gridList==0 >
<#list appList as app>
<#if (app_index)%4==0>
<div class="row">
</#if>
<div class="col-3 appListGrid">
<table>
<tr><td>
<a target="_blank" title="${app.name}"
<#if "SP"==app.inducer>
href="${app.loginUrl}"
</#if>
<#if "IDP"==app.inducer>
href="<@base/>/authz/${app.id}"
</#if> >
<img src="${app.iconBase64}" title="${app.name}" class="appListimage"/>
</a><br>
${app.name}
</td></tr>
</table>
</div>
<#if (app_index +1)%4==0>
</div>
</#if>
</#list>
<#if (appList?size)%4!=0>
</div >
</#if>
<#else>
<div class="row">
<div class="col-12">
<table class="table appListTable table-hover">
<thead>
<tr>
<th>
<@locale code="apps.number"/>
</th>
<th>
<@locale code="apps.icon"/>
</th>
<th ><@locale code="apps.name"/></td>
<th>
<@locale code="button.text.action"/>
</th>
</tr>
</thead>
<#list appList as app>
<tr class="">
<td>${app_index +1 }</td>
<td>
<a
<#if "SP"==app.inducer>
href="${app.loginUrl}"
</#if>
<#if "IDP"==app.inducer>
href="<@base/>/authz/${app.id}"
</#if>
target="_blank" title="${app.name}" >
<img src="${app.iconBase64}" title="${app.name}" class="appListimage"/>
</a>
</td>
<td style="">${app.name}</td>
<td>
<a
<#if "SP"==app.inducer>
href="${app.loginUrl}"
</#if>
<#if "IDP"==app.inducer>
href="<@base/>/authz/${app.id}"
</#if>
target="_blank" title="${app.name}" >
<@locale code="button.text.visit"/>
</a>
</td>
</tr>
</#list>
</table>
</div>
</#if>
</div>
</div>
<div id="footer">
<#include "../layout/footer.ftl"/>
</div>
<body>
</html>

View File

@@ -1,47 +0,0 @@
<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<#include "../layout/header.ftl"/>
<#include "../layout/common.cssjs.ftl"/>
<script type="text/javascript">
</script>
<style type="text/css">
.table th, .table td {
padding: .2rem;
vertical-align: middle;
}
</style>
</head>
<body>
<!-- content -->
<form id="actionForm" name="credentialsubmit" action="<@base/>/appUserConfig" method="post" class="needs-validation" novalidate>
<input type="hidden" id="protocol" name="protocol" value="${protocol}" />
<input type="hidden" id="credential" name="credential" value="${credential}" />
<table class="table table-bordered">
<tr <#if false==username>style="display:none"</#if>>
<td><@locale code="account.relatedUsername" /></td>
<td><input class="form-control" type="text" id="identity_username" name="identity_username" value="${identity_username!}" required="" /></td>
</tr>
<tr <#if false==password> style="display:none"</#if> >
<td><@locale code="account.relatedPassword" /></td>
<td><input class="form-control" type="password" id="identity_password" name="identity_password" value="${identity_password!}" required=""/></td>
</tr>
<tr style="display:none">
<td>uid</td>
<td><input class="form-control" type="text" id="userId" name="userId" value="${userId}" /></td>
</tr>
<tr style="display:none">
<td>appId</td>
<td><input class="form-control" type="text" id="appId" name="appId" value="${appId}" /></td>
</tr>
<tr>
<td colspan="2"><input class="button btn btn-primary mr-3" type="submit" style="width: 400px" id="credentialsubmitbutton"value="<@locale code="button.text.save" />"/></td>
</tr>
</table>
</form>
</body>
</html>

View File

@@ -1,13 +0,0 @@
<!DOCTYPE HTML >
<html>
<head>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
<title>${notice.title}</title>
<base href="<@base />"/>
<link rel="shortcut icon" type="image/x-icon" href="<@base />/static/images/favicon.ico"/>
<link type="text/css" rel="stylesheet" href="<@base url="/style.css"/>" />
</head>
<body>
${notice.content}
</body>
</html>

View File

@@ -1,79 +0,0 @@
<!DOCTYPE HTML >
<html>
<head>
<#include "layout/header.ftl"/>
<#include "layout/common.cssjs.ftl"/>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title><@locale code="login.password.expired" /></title>
</head>
<body>
<div id="top">
<#include "layout/nologintop.ftl"/>
</div>
<div id="content">
<div class="container">
<table width="100%">
<tr>
<td>
<div>
<form method="post" type="label" autoclose="true" action="<@base/>/safe/changeExpiredPassword">
<table class="table table-bordered" >
<tbody>
<tr>
<th colspan="2">
<@locale code="login.password.expired.tip" />
</th>
</tr>
<tr <#if ''==errorMessage>style="display:none;"</#if>>
<th colspan="2" style="color:red;">
${errorMessage!}
</th>
</tr>
<tr>
<th><@locale code="userinfo.displayName" /> </th>
<td>
<input readonly type="text" id="displayName" name="displayName" class="form-control" title="" value="${model.displayName}"/>
</td>
</tr>
<tr>
<th><@locale code="userinfo.username" /> </th>
<td>
<input readonly type="text" id="username" name="username" class="form-control" title="" value="${model.username}"/>
</td>
</tr>
<tr>
<th><@locale code="login.password.newPassword" /></th>
<td>
<input type="password" id="newPassword" name="newPassword" class="form-control" title="" value="" required="" />
</td>
</tr>
<tr>
<th><@locale code="login.password.confirmPassword" /></th>
<td nowrap>
<input type="password" id="confirmPassword" name="confirmPassword" class="form-control" title="" value="" required="" />
</td>
</tr>
<tr>
<td colspan="2" class="center">
<input id="_method" type="hidden" name="_method" value="post"/>
<input class="button btn btn-lg btn-primary" style="width:100px" type="submit" id="submitBtn" value="<@locale code="button.text.save" />"/>
</td>
</tr>
</tbody>
</table>
</form>
</div>
</td>
</tr>
</table>
</div>
</div>
<div id="footer">
<#include "layout/footer.ftl"/>
</div>
</body>
</html>

View File

@@ -1,76 +0,0 @@
<!DOCTYPE HTML >
<html>
<head>
<#include "layout/header.ftl"/>
<#include "layout/common.cssjs.ftl"/>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title><@locale code="login.password.initial.change.tip" /></title>
</head>
<body>
<div id="top">
<#include "layout/nologintop.ftl"/>
</div>
<div id="content">
<div class="container">
<table width="100%">
<tr>
<td>
<form method="post" type="label" autoclose="true" action="<@base/>/safe/changeInitPassword">
<table class="table table-bordered" >
<tbody>
<tr>
<th colspan="2"><@locale code="login.password.initial.change.tip" /></th>
</tr>
<tr <#if ''==errorMessage>style="display:none;"</#if>>
<th colspan="2" style="color:red;">
${errorMessage!}
</th>
</tr>
<tr>
<th><@locale code="userinfo.displayName" /> </th>
<td>
<input readonly type="text" id="displayName" name="displayName" class="form-control" title="" value="${model.displayName}"/>
</td>
</tr>
<tr>
<th><@locale code="userinfo.username" /> </th>
<td>
<input readonly type="text" id="username" name="username" class="form-control" title="" value="${model.username}"/>
</td>
</tr>
<tr>
<th><@locale code="login.password.newPassword" /></th>
<td>
<input type="password" id="newPassword" name="newPassword" class="form-control" title="" value="" required="" />
</td>
</tr>
<tr>
<th><@locale code="login.password.confirmPassword" /></th>
<td nowrap>
<input type="password" id="confirmPassword" name="confirmPassword" class="form-control" title="" value="" required="" />
</td>
</tr>
<tr>
<td colspan="2" class="center">
<input id="_method" type="hidden" name="_method" value="post"/>
<input class="button btn btn-lg btn-primary" style="width:100px" type="submit" id="submitBtn" value="<@locale code="button.text.save" />"/>
</td>
</tr>
</tbody>
</table>
</form>
</td>
</tr>
</table>
</div>
</div>
<div id="footer">
<#include "layout/footer.ftl"/>
</div>
</body>
</html>

View File

@@ -1,29 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<@base/>">
<title>My JSP 'activated.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
</head>
<body>
<div id="main" class="container">
<#if 0 == activate>
url expired.
</#if>
<#if 1 == activate>
activate success,
<a href='<@base url="/"/>'>
<@locale code="login.button.login"/>
</a>
</#if>
</div>
</body>
</html>

View File

@@ -1,73 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<@base/>">
<title>My JSP 'activated.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
</head>
<body>
<div id="main" class="container">
<#if null != model>
<table border="0" style="width:100%;">
<tr>
<td width="630px">
</td>
<td>
<form action="<@base />/signup/activate/${model.id}" method="post">
<table class="datatable">
<tr>
<td><@locale code="register.lastname"/></td>
<td>${model.lastName}</td>
</tr>
<tr>
<td><@locale code="register.firstname"/></td>
<td>${model.firstName}</td>
</tr>
<tr>
<td><@locale code="register.workemail"/></td>
<td>${model.workEmail}</td>
</tr>
<tr>
<td><@locale code="register.company"/></td>
<td>${model.company}</td>
</tr>
<tr>
<td><@locale code="register.workphone"/></td>
<td>${model.workPhone}</td>
</tr>
<tr>
<td><@locale code="register.password"/></td>
<td><input type='password' id="password" name="password" value="" /></td>
</tr>
<tr>
<td><@locale code="register.confirmpassword"/></td>
<td><input type='password' id="confirmpassword" name="confirmpassword" value="" /></td>
</tr>
<tr style="display:none">
<td><@locale code="register.users"/></td>
<td><input type='text' id="users" name="users" value="0" /></td>
</tr>
<tr>
<td colspan="2"><input id="registerBtn" class="button" type="submit" value="<@locale code="button.text.enable" />"/></td>
</tr>
</table>
</form>
</td>
</tr>
</table>
</#if>
<#if null == model>
url expired.
</#if>
</div>
</body>
</html>

View File

@@ -1,59 +0,0 @@
<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<#include "../layout/header.ftl">
<#include "../layout/common.cssjs.ftl">
</head>
<body >
<div id="top">
<#include "../layout/nologintop.ftl">
</div>
<div id="main" class="container">
<div class="row">
<div class="col-md-2"></div>
<div class="col-md-8">
<form id="actionForm"
action="<@base/>/signup/registeron"
forward="<@base/>/login"
method="post" class="needs-validation" novalidate>
<table class="table table-bordered">
<tr>
<td><@locale code="forgotpassword.emailmobile"/></td>
<td><input required="" type="text" id="emailMobile" name="emailMobile" class="form-control" title="" value=""/></td>
</tr>
<tr>
<td><@locale code="login.text.captcha"/></td>
<td><input required="" class="form-control" type='text' id="j_captcha" name="captcha" tabindex="3" value="" style="float: left;"/><img id="j_captchaimg" class="captcha-image" src="<@base/>/captcha"/></td>
</tr>
<tr>
<td><@locale code="userinfo.displayName"/></td>
<td><input required="" class="form-control" type='text' id='displayName' name='displayName' tabindex="1"/></td>
</tr>
<tr>
<td><@locale code="userinfo.username"/></td>
<td><input required="" class="form-control" type='text' id='username' name='username' tabindex="1"/></td>
</tr>
<tr>
<td><@locale code="login.text.password"/></td>
<td><input required="" class="form-control" type='password' id="password" name="password" tabindex="1" value="" /></td>
</tr>
<tr>
<td><@locale code="login.password.confirmPassword"/></td>
<td><input required="" class="form-control" type='password' id="confirmpassword" name="confirmpassword" tabindex="2" value="" /></td>
</tr>
<tr>
<td colspan="2"><input class="button btn btn-lg btn-primary btn-block" type="submit" value="<@locale code="login.text.register" />"/></td>
</tr>
</table>
</form>
</div>
<div class="col-md-2"></div>
</div >
</div>
<div id="footer">
<#include "../layout/footer.ftl">
</div>
</body>
</html>

View File

@@ -1,66 +0,0 @@
<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<#include "../layout/header.ftl">
<#include "../layout/common.cssjs.ftl">
</head>
<body >
<div id="top">
<#include "../layout/nologintop.ftl">
</div>
<div id="main" class="container">
<div class="row">
<div class="col-md-2"></div>
<div class="col-md-8">
<form id="actionForm"
action="<@base/>/signup/register"
forward="<@base/>/login"
method="post" class="needs-validation" novalidate>
<table class="table table-bordered">
<tr>
<td><@locale code="register.displayName"/></td>
<td><input required="" class="form-control" type='text' id='displayName' name='displayName' tabindex="1"/></td>
</tr>
<tr>
<td><@locale code="register.workEmail"/></td>
<td><input required="" type="text" id="workEmail" name="workEmail" class="form-control" title="" value="" tabindex="2"/></td>
</tr>
<tr>
<td><@locale code="register.workPhone"/></td>
<td><input required="" type="text" id="workPhone" name="workPhone" class="form-control" title="" value="" tabindex="3"/></td>
</tr>
<tr>
<td><@locale code="register.instName"/></td>
<td><input required="" class="form-control" type='text' id='instName' name='instName' tabindex="4"/></td>
</tr>
<tr>
<td><@locale code="register.employees"/></td>
<td>
<select class="form-control" name="employees" >
<option value="20" selected ><@locale code="register.employees.20" /></option>
<option value="100" ><@locale code="register.employees.100" /></option>
<option value="500" ><@locale code="register.employees.500" /></option>
<option value="1000" ><@locale code="register.employees.1000" /></option>
<option value="2000" ><@locale code="register.employees.2000" /></option>
</select>
</td>
</tr>
<tr>
<td><@locale code="login.text.captcha"/></td>
<td><input required="" class="form-control" type='text' id="j_captcha" name="captcha" tabindex="6" value="" style="float: left;"/><img id="j_captchaimg" class="captcha-image" src="<@base/>/captcha"/></td>
</tr>
<tr>
<td colspan="2"><input class="button btn btn-lg btn-primary btn-block" type="submit" value="<@locale code="login.text.register" />"/></td>
</tr>
</table>
</form>
</div>
<div class="col-md-2"></div>
</div >
</div>
<div id="footer">
<#include "../layout/footer.ftl">
</div>
</body>
</html>

View File

@@ -1,30 +0,0 @@
<!DOCTYPE HTML >
<html>
<head>
<base href="<@base/>">
<title>Registered</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="Registered">
</head>
<body>
<#if 2==registered>
company ${company} registered,please change company name.<br>
<input type="button" class="button" value="后退" onclick="javascript:history.go(-1);">
</#if>
<#if 1==registered>
please activate by you email .
</#if>
<#if 0==registered>
please activate by you email .
</#if>
</body>
</html>

View File

@@ -1,72 +0,0 @@
<!DOCTYPE HTML >
<html>
<head>
<#include "../layout/header.ftl"/>
<#include "../layout/common.cssjs.ftl"/>
</head>
<body>
<#include "../layout/top.ftl"/>
<#include "../layout/nav_primary.ftl"/>
<div id="main" class="container">
<div class="row">
<div class="col-md-1"></div>
<div class="col-md-10">
<form id="actionForm" method="post" type="label" autoclose="true" action="<@base/>/safe/changeAppLoginPasswod">
<table class="table table-bordered" >
<tbody>
<tr>
<th colspan="2"><@locale code="login.password.applogin.changepassword" /></th>
</tr>
<tr>
<th><@locale code="userinfo.displayName" /> </th>
<td>
<input class="form-control" readonly type="text" id="displayName" name="displayName" class="required" title="" value="${model.displayName}"/>
</td>
</tr>
<tr>
<th><@locale code="userinfo.username" /> </th>
<td>
<input class="form-control" readonly type="text" id="username" name="username" class="required" title="" value="${model.username}"/>
</td>
</tr>
<tr>
<th><@locale code="login.password.oldPassword" /> </th>
<td>
<input class="form-control" type="password" id="oldPassword" name="oldPassword" class="required" title="" value=""/>
</td>
</tr>
<tr>
<th><@locale code="login.password.newPassword" /></th>
<td>
<input class="form-control" type="password" id="newPassword" name="newPassword" class=" required" title="" value=""/>
</td>
</tr>
<tr>
<th><@locale code="login.password.confirmPassword" /></th>
<td nowrap>
<input class="form-control" type="password" id="confirmPassword" name="confirmPassword" class="{ required: true, equalTo: '#newPassword' }" title="" value=""/>
</td>
</tr>
<tr>
<td colspan="2" class="center">
<input id="_method" type="hidden" name="_method" value="post"/>
<input class="button btn btn-primary" style="width:100px" type="button" id="submitBtn" value="<@locale code="button.text.save" />"/>
</td>
</tr>
</tbody>
</table>
</form>
</div>
<div class="col-md-1"></div>
</div >
</div>
<div id="footer">
<#include "../layout/footer.ftl"/>
</div>
<body>
</html>

View File

@@ -1,71 +0,0 @@
<!DOCTYPE HTML >
<html>
<head>
<#include "../layout/header.ftl"/>
<#include "../layout/common.cssjs.ftl"/>
</head>
<body>
<#include "../layout/top.ftl"/>
<#include "../layout/nav_primary.ftl"/>
<div id="main" class="container">
<div class="row">
<div class="col-md-1"></div>
<div class="col-md-10">
<form id="actionForm" method="post" action="<@base/>/safe/changePassword" class="needs-validation" novalidate>
<table class="table table-bordered" >
<tbody>
<tr>
<th colspan="2"><@locale code="login.password.changepassword" /></th>
</tr>
<tr>
<th><@locale code="userinfo.displayName" /> </th>
<td>
<input class="form-control" readonly type="text" id="displayName" name="displayName" class="required" title="" value="${model.displayName}"/>
</td>
</tr>
<tr>
<th><@locale code="userinfo.username" /> </th>
<td>
<input class="form-control" readonly type="text" id="username" name="username" class="required" title="" value="${model.username}"/>
</td>
</tr>
<tr>
<th><@locale code="login.password.oldPassword" /> </th>
<td>
<input class="form-control" type="password" id="oldPassword" name="oldPassword" title="" value="" required="" />
</td>
</tr>
<tr>
<th><@locale code="login.password.newPassword" /></th>
<td>
<input class="form-control" type="password" id="newPassword" name="newPassword" title="" value="" required="" />
</td>
</tr>
<tr>
<th><@locale code="login.password.confirmPassword" /></th>
<td nowrap>
<input class="form-control" type="password" id="confirmPassword" name="confirmPassword" title="" value="" required="" />
</td>
</tr>
<tr>
<td colspan="2" class="center">
<input id="_method" type="hidden" name="_method" value="post"/>
<input id="submitBtn" class="button btn btn-primary" style="width:100px" type="submit" value="<@locale code="button.text.save" />"/>
</td>
</tr>
</tbody>
</table>
</form>
</div>
<div class="col-md-1"></div>
</div >
</div>
<div id="footer">
<#include "../layout/footer.ftl"/>
</div>
<body>
</html>

View File

@@ -1,113 +0,0 @@
<!DOCTYPE HTML >
<html>
<head>
<#include "../layout/header.ftl"/>
<#include "../layout/common.cssjs.ftl"/>
</head>
<body>
<#include "../layout/top.ftl"/>
<#include "../layout/nav_primary.ftl"/>
<div id="main" class="container">
<div class="row">
<div class="col-md-1"></div>
<div class="col-md-10">
<form id="actionForm" method="post" type="label" autoclose="true" action="<@base/>/safe/setting" class="needs-validation" novalidate>
<table class="table table-bordered" style="width:100%;">
<tbody>
<tr>
<th colspan="2"><@locale code="userinfo.authnType" /></th>
</tr>
<tr>
<th><@locale code="userinfo.displayName" /> </th>
<td >
<input class="form-control" readonly type="text" id="displayName" name="displayName" class="required" title="" value="${model.displayName}"/>
</td>
</tr>
<tr>
<th><@locale code="userinfo.username" /> </th>
<td>
<input class="form-control" readonly type="text" id="username" name="username" class="required" title="" value="${model.username}"/>
</td>
</tr>
<tr>
<th><@locale code="userinfo.authnType" /></th>
<td nowrap>
<select class="form-control form-select" name="authnType" id="authnType">
<option value="0" <#if 0==model.authnType >selected</#if> ><@locale code="button.text.select" /></option>
<option value="1" <#if 1==model.authnType >selected</#if> ><@locale code="userinfo.authnType.authnType.1" /></option>
<!--
<option value="2" <#if 2==model.authnType >selected</#if> ><@locale code="userinfo.authnType.authnType.2" /></option>
-->
<option value="3" <#if 3==model.authnType >selected</#if> ><@locale code="userinfo.authnType.authnType.3" /></option>
<option value="4" <#if 4==model.authnType >selected</#if> ><@locale code="userinfo.authnType.authnType.4" /></option>
<option value="5" <#if 5==model.authnType >selected</#if> ><@locale code="userinfo.authnType.authnType.5" /></option>
<!--
<option value="6" <#if 6==model.authnType >selected</#if> ><@locale code="userinfo.authnType.authnType.6" /></option>
<option value="7" <#if 7==model.authnType >selected</#if> ><@locale code="userinfo.authnType.authnType.7" /></option>
<option value="8" <#if 8==model.authnType >selected</#if> ><@locale code="userinfo.authnType.authnType.8" /></option>
<option value="9" <#if 9==model.authnType >selected</#if> ><@locale code="userinfo.authnType.authnType.9" /></option>
<option value="10" <#if 10==model.authnType>selected</#if> ><@locale code="userinfo.authnType.authnType.10" /></option>
-->
</select>
</td>
</tr>
<tr>
<th><@locale code="userinfo.mobile" /> </th>
<td>
<input class="form-control" type="text" id="mobile" name="mobile" required title="" value="${model.mobile}" required="" />
<label for="mobile"></label>
</td>
</tr>
<tr style="display:none;">
<th>Verify Code :</th>
<td>
<input class="form-control" type="text" id="mobileVerify" name="mobileVerify" required title="" value="1" style="width:200px" /><input class="button" style="width:100px" type="button" id="getMobileVerifyBtn" value="get Verify"/>
<label for="verify"></label>
</td>
</tr>
<tr>
<th><@locale code="userinfo.email" /> </th>
<td>
<input class="form-control" type="text" id="email" name="email" class="required" title="" value="${model.email}" required="" />
<label for="eamil"></label>
</td>
</tr>
<tr style="display:none;">
<th>Verify Code :</th>
<td>
<input class="form-control" type="text" id="emailVerify" name="emailVerify" class="required" title="" value="Verify" style="width:200px" /><input class="button" style="width:100px" type="button" id="getEmailVerifyBtn" value="get Verify"/>
<label for="verify"></label>
</td>
</tr>
<tr>
<th><@locale code="userinfo.theme" /></th>
<td nowrap>
<select class="form-control form-select" name="theme" id="theme">
<option value="default" <#if "default"==model.theme >selected</#if> ><@locale code="userinfo.theme.default" /></option>
<option value="minty" <#if "minty" ==model.theme >selected</#if> ><@locale code="userinfo.theme.minty" /></option>
<option value="pulse" <#if "pulse" ==model.theme >selected</#if> ><@locale code="userinfo.theme.pulse" /></option>
</select>
</td>
</tr>
<tr>
<td colspan="2" class="center">
<input id="_method" type="hidden" name="_method" value="post"/>
<input class="button btn btn-primary" style="width:100px" type="submit" id="submitBtn" value="<@locale code="button.text.save" />"/>
</td>
</tr>
</tbody>
</table>
</form>
</div>
<div class="col-md-1"></div>
</div >
</div>
<div id="footer">
<#include "../layout/footer.ftl"/>
</div>
<body>
</html>

View File

@@ -1,80 +0,0 @@
<!DOCTYPE HTML >
<html>
<head>
<#include "../layout/header.ftl"/>
<#include "../layout/common.cssjs.ftl"/>
</head>
<body>
<#include "../layout/top.ftl"/>
<#include "../layout/nav_primary.ftl"/>
<div id="main" class="container">
<div class="row">
<div class="col-md-12">
<@locale code="login.totp.title" />
</div>
</div>
<div class="row">
<div class="col-md-6">
<img id="captchaimg" src="<@base/>/image/${id}" /><br>
支持<b>Google Authenticator等</b>
</div>
<div class="col-md-6">
<table class="table table-bordered" >
<tr>
<th style="width:30%;"><@locale code="userinfo.displayName" /> </th>
<td>
<input readonly type="text" class="required form-control" title="" value="${userInfo.displayName}"/>
</td>
</tr>
<tr>
<th><@locale code="userinfo.username" /> </th>
<td>
<input readonly type="text" class="required form-control" title="" value="${userInfo.username}"/>
</td>
</tr>
<tr>
<th><@locale code="login.totp.sharedSecret" />(BASE32) </th>
<td>
<input readonly type="text" class="required form-control" title="" value="${sharedSecret}"/>
</td>
</tr>
<tr>
<th><@locale code="login.totp.sharedSecret" />(HEX) </th>
<td>
<input readonly type="text" class="required form-control" title="" value="${hexSharedSecret}"/>
</td>
</tr>
<tr>
<th><@locale code="login.totp.period" /></th>
<td>
<input readonly type="text" class="required form-control" title="" value="${format.period}"/>
</td>
</tr>
<tr>
<th><@locale code="login.totp.digits" /></th>
<td>
<input readonly type="text" class="required form-control" title="" value="${format.digits}"/>
</td>
</tr>
<tr>
<th><@locale code="login.totp.crypto" /></th>
<td>
<input readonly type="text" class="required form-control" title="" value="${format.crypto}"/>
</td>
</tr>
<tr>
<td colspan="2" class="center">
<input class="button forward btn btn-primary" style="width:100px" wurl="<@base/>/safe/otp/gen/timebased" type="button" id="forward" value="<@locale code="login.totp.generate" />"/>
</td>
</tr>
</table>
</div>
</div>
<div id="footer">
<#include "../layout/footer.ftl"/>
</div>
<body>
</html>

View File

@@ -1,48 +0,0 @@
<!DOCTYPE HTML >
<html>
<head>
<#include "../layout/header.ftl"/>
<#include "../layout/common.cssjs.ftl"/>
</head>
<body>
<#include "../layout/top.ftl"/>
<#include "../layout/nav_primary.ftl"/>
<div id="main" class="container">
<table data-toggle="table">
<thead>
<tr>
<!--<th><@locale code="login.social.sortorder" /></th>-->
<th><@locale code="login.social.icon" /></th>
<th><@locale code="login.social.provider" /></th>
<th><@locale code="login.social.bindtime" /></th>
<th><@locale code="login.social.lastLoginTime" /></th>
<th><@locale code="login.social.action" /></th>
</tr>
</thead>
<tbody>
<#list listSocialSignOnProvider as socialSignOnProvider>
<tr>
<!--<td>${socialSignOnProvider.sortIndex}</td>-->
<td><img src="<@base />/static/${socialSignOnProvider.icon}" title="${socialSignOnProvider.providerName}" width="32px;" height="32px;"/></td>
<td>${socialSignOnProvider.providerName}</td>
<td>${socialSignOnProvider.bindTime!}</td>
<td>${socialSignOnProvider.lastLoginTime!}</td>
<td>
<#if false==socialSignOnProvider.userBind>
<a href="<@base/>/logon/oauth20/bind/${socialSignOnProvider.provider}"><@locale code="login.social.link" /></a>
</#if>
<#if true==socialSignOnProvider.userBind>
<a href="<@base />/logon/oauth20//unbind/${socialSignOnProvider.provider}"><@locale code="login.social.unlink" /></a>
</#if>
</td>
</tr>
</#list>
</tbody>
</table>
</div >
<div id="footer">
<#include "../layout/footer.ftl"/>
</div>
<body>
</html>

View File

@@ -1,27 +0,0 @@
<!DOCTYPE HTML >
<html>
<head>
<#include "layout/header.ftl"/>
<#include "layout/common.cssjs.ftl"/>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title><@locale code="login.session.timeout.tip"/></title>
</head>
<body>
<div id="top">
<#include "layout/nologintop.ftl"/>
</div>
<div id="content">
<h2><@locale code="login.session.timeout.tip"/></h2>
<p>
<@locale code="login.session.timeout.prefix"/>
<a href="${reloginUrl}">
<@locale code="login.session.timeout.suffix"/>
</a>.
</p>
</div>
<div id="footer">
<#include "layout/footer.ftl"/>
</div>
</body>
</html>