This commit is contained in:
shimingxy
2019-04-29 23:53:10 +08:00
parent 0650b25b8b
commit 055bed6a58
5255 changed files with 619669 additions and 0 deletions
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin"/>
</classpath>
+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>maxkey-authentications</name>
<comment>Project maxkey-authentications created by Buildship.</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.wst.common.project.facet.core.builder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.springframework.ide.eclipse.boot.validation.springbootbuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.wst.validation.validationbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
</natures>
</projectDescription>
@@ -0,0 +1,11 @@
build.commands=org.eclipse.jdt.core.javabuilder
connection.arguments=
connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
connection.java.home=null
connection.jvm.arguments=
connection.project.dir=..
containers=org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7/
derived.resources=.gradle,build
eclipse.preferences.version=1
natures=org.eclipse.jdt.core.javanature
project.path=\:maxkey-authentications
@@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8
@@ -0,0 +1,24 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.builder.cleanOutputFolder=clean
org.eclipse.jdt.core.builder.duplicateResourceTask=warning
org.eclipse.jdt.core.builder.invalidClasspath=abort
org.eclipse.jdt.core.builder.recreateModifiedClassFileInOutputFolder=ignore
org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=
org.eclipse.jdt.core.circularClasspath=warning
org.eclipse.jdt.core.classpath.exclusionPatterns=enabled
org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled
org.eclipse.jdt.core.classpath.outputOverlappingAnotherSource=error
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.maxProblemPerUnit=100
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.8
org.eclipse.jdt.core.incompatibleJDKLevel=ignore
org.eclipse.jdt.core.incompleteClasspath=error
@@ -0,0 +1,2 @@
eclipse.preferences.version=1
org.eclipse.jdt.launching.PREF_STRICTLY_COMPATIBLE_JRE_NOT_AVAILABLE=warning
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">
<wb-module deploy-name="maxkey-authentications">
<wb-resource deploy-path="/" source-path="/src/main/java"/>
</wb-module>
</project-modules>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<faceted-project>
<fixed facet="java"/>
<fixed facet="jst.utility"/>
<installed facet="jst.utility" version="1.0"/>
<installed facet="java" version="1.8"/>
</faceted-project>
@@ -0,0 +1,2 @@
boot.validation.initialized=true
eclipse.preferences.version=1
+29
View File
@@ -0,0 +1,29 @@
description = "maxkey-authentications"
dependencies {
//local jars
compile fileTree(dir: '../maxkey-lib/spring/', include: '*.jar')
compile fileTree(dir: '../maxkey-lib/spring-security/', include: '*.jar')
compile fileTree(dir: '../maxkey-lib/apache/', include: '*.jar')
compile fileTree(dir: '../maxkey-lib/db/', include: '*.jar')
compile fileTree(dir: '../maxkey-lib/tiles/', include: '*.jar')
compile fileTree(dir: '../maxkey-lib/common/', include: '*.jar')
compile fileTree(dir: '../maxkey-lib/opensaml/', include: '*.jar')
compile fileTree(dir: '../maxkey-lib/xml/', include: '*.jar')
compile fileTree(dir: '../maxkey-lib/json/', include: '*.jar')
compile fileTree(dir: '../maxkey-lib/log/', include: '*.jar')
compile fileTree(dir: '../maxkey-lib/java/', include: '*.jar')
compile fileTree(dir: '../maxkey-lib/other/', include: '*.jar')
compile project(":maxkey-core")
compile project(":maxkey-dao")
compile project(":maxkey-jose-jwt")
compile project(":maxkey-client-sdk")
compile project(":maxkey-protocols:maxkey-protocol-oauth-2.0")
compile project(":maxkey-protocols:maxkey-protocol-saml-2.0")
}
@@ -0,0 +1,3 @@
Manifest-Version: 1.0
Class-Path:
@@ -0,0 +1 @@
package org.maxkey.authn;
@@ -0,0 +1,62 @@
package org.maxkey.authn.realm.activedirectory;
import java.util.List;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.maxkey.authn.realm.AbstractAuthenticationRealm;
import org.maxkey.authn.realm.IAuthenticationServer;
import org.maxkey.domain.UserInfo;
import org.maxkey.web.WebContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.authentication.BadCredentialsException;
public class ActiveDirectoryAuthenticationRealm extends AbstractAuthenticationRealm{
private final static Logger _logger = LoggerFactory.getLogger(ActiveDirectoryAuthenticationRealm.class);
@NotNull
@Size(min=1)
private List<IAuthenticationServer> activeDirectoryServers;
/**
*
*/
public ActiveDirectoryAuthenticationRealm() {
super();
}
/**
* @param jdbcTemplate
*/
public ActiveDirectoryAuthenticationRealm(JdbcTemplate jdbcTemplate) {
super(jdbcTemplate);
}
@Override
public boolean passwordMatches(UserInfo userInfo, String password) {
boolean isAuthenticated=false;
for (final IAuthenticationServer activeDirectoryServer : this.activeDirectoryServers) {
_logger.debug("Attempting to authenticate {} at {}", userInfo.getUsername(), activeDirectoryServer);
isAuthenticated= activeDirectoryServer.authenticate(userInfo.getUsername(), password);
if (isAuthenticated ) {
return true;
}
}
if(!isAuthenticated){
throw new BadCredentialsException(WebContext.getI18nValue("login.error.password"));
}
return false;
}
public void setActiveDirectoryServers(
List<IAuthenticationServer> activeDirectoryServers) {
this.activeDirectoryServers = activeDirectoryServers;
}
}
@@ -0,0 +1,56 @@
/**
*
*/
package org.maxkey.authn.realm.activedirectory;
import org.maxkey.authn.realm.IAuthenticationServer;
import org.maxkey.persistence.ldap.ActiveDirectoryUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Crystal.Sea
*
*/
public final class ActiveDirectoryServer implements IAuthenticationServer {
private final static Logger _logger = LoggerFactory.getLogger(ActiveDirectoryServer.class);
ActiveDirectoryUtils activeDirectoryUtils;
String filter;
/* (non-Javadoc)
* @see com.connsec.web.authentication.realm.IAuthenticationServer#authenticate(java.lang.String, java.lang.String)
*/
@Override
public boolean authenticate(String username, String password) {
ActiveDirectoryUtils ldapPassWordValid = new ActiveDirectoryUtils(activeDirectoryUtils.getProviderUrl(),
activeDirectoryUtils.getDomain()+"\\" + username, password,activeDirectoryUtils.getDomain());
ldapPassWordValid.openConnection();
if(ldapPassWordValid.getCtx()!=null){
_logger.debug("Active Directory user " + username + " is validate .");
ldapPassWordValid.close();
return true;
}
ldapPassWordValid.close();
return false;
}
public ActiveDirectoryUtils getActiveDirectoryUtils() {
return activeDirectoryUtils;
}
public void setActiveDirectoryUtils(ActiveDirectoryUtils activeDirectoryUtils) {
this.activeDirectoryUtils = activeDirectoryUtils;
}
public String getFilter() {
return filter;
}
public void setFilter(String filter) {
this.filter = filter;
}
}
@@ -0,0 +1,60 @@
package org.maxkey.authn.realm.ldap;
import java.util.List;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.maxkey.authn.realm.AbstractAuthenticationRealm;
import org.maxkey.authn.realm.IAuthenticationServer;
import org.maxkey.domain.UserInfo;
import org.maxkey.web.WebContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.authentication.BadCredentialsException;
public class LdapAuthenticationRealm extends AbstractAuthenticationRealm{
private final static Logger _logger = LoggerFactory.getLogger(LdapAuthenticationRealm.class);
@NotNull
@Size(min=1)
private List<IAuthenticationServer> ldapServers;
/**
*
*/
public LdapAuthenticationRealm() {
}
/**
* @param jdbcTemplate
*/
public LdapAuthenticationRealm(JdbcTemplate jdbcTemplate) {
super(jdbcTemplate);
}
@Override
public boolean passwordMatches(UserInfo userInfo, String password) {
boolean isAuthenticated=false;
for (final IAuthenticationServer ldapServer : this.ldapServers) {
_logger.debug("Attempting to authenticate {} at {}", userInfo.getUsername(), ldapServer);
isAuthenticated= ldapServer.authenticate(userInfo.getUsername(), password);
if (isAuthenticated ) {
return true;
}
}
if(!isAuthenticated){
throw new BadCredentialsException(WebContext.getI18nValue("login.error.password"));
}
return false;
}
public void setLdapServers(List<IAuthenticationServer> ldapServers) {
this.ldapServers = ldapServers;
}
}
@@ -0,0 +1,81 @@
/**
*
*/
package org.maxkey.authn.realm.ldap;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import org.maxkey.authn.realm.IAuthenticationServer;
import org.maxkey.persistence.ldap.LdapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Crystal.Sea
*
*/
public final class LdapServer implements IAuthenticationServer {
private final static Logger _logger = LoggerFactory.getLogger(LdapServer.class);
LdapUtils ldapUtils;
String filterAttribute;
/* (non-Javadoc)
* @see com.connsec.web.authentication.realm.IAuthenticationServer#authenticate(java.lang.String, java.lang.String)
*/
@Override
public boolean authenticate(String username, String password) {
String queryFilter = "("+filterAttribute+"="+username+")";
_logger.info(" filter : " + queryFilter);
String dn="";
SearchControls constraints = new SearchControls();
constraints.setSearchScope(ldapUtils.getSearchScope());
try {
NamingEnumeration<SearchResult> results = ldapUtils.getConnection()
.search(ldapUtils.getBaseDN(), queryFilter, constraints);
if (results == null || !results.hasMore()) {
_logger.error("Ldap user "+username +" not found . ");
return false;
}else{
while (results != null && results.hasMore()) {
SearchResult sr = (SearchResult) results.next();
//String rdn = sr.getName();
dn = sr.getNameInNamespace();
_logger.debug("Directory user dn is "+dn+" .");
}
}
} catch (NamingException e) {
_logger.error("query throw NamingException:" + e.getMessage());
} finally {
ldapUtils.close();
}
LdapUtils ldapPassWordValid=new LdapUtils(ldapUtils.getProviderUrl(),dn,password);
ldapPassWordValid.openConnection();
if(ldapPassWordValid.getCtx()!=null){
_logger.debug("Directory user " + username + " is validate .");
ldapPassWordValid.close();
return true;
}
return false;
}
public LdapUtils getLdapUtils() {
return ldapUtils;
}
public void setLdapUtils(LdapUtils ldapUtils) {
this.ldapUtils = ldapUtils;
}
public String getFilterAttribute() {
return filterAttribute;
}
public void setFilterAttribute(String filterAttribute) {
this.filterAttribute = filterAttribute;
}
}
@@ -0,0 +1,62 @@
package org.maxkey.authn.realm.radius;
/**
* RADIUS protocol enumeration.
*
*/
public enum RadiusProtocol {
/** The chap. */
CHAP("chap"),
/** The EA p_ m d5. */
EAP_MD5("eap-md5"),
/** The EA p_ mscha pv2. */
EAP_MSCHAPv2("eap-mschapv2"),
/** The eap tls. */
EAP_TLS("eap-tls"),
/** The eap ttls pap. */
EAP_TTLS_PAP("eap-ttls:innerProtocol=pap"),
/** The EA p_ ttl s_ ea p_ m d5. */
EAP_TTLS_EAP_MD5("eap-ttls:innerProtocol=eap-md5"),
/** The EA p_ ttl s_ ea p_ mscha pv2. */
EAP_TTLS_EAP_MSCHAPv2("eap-ttls:innerProtocol=eap-mschapv2"),
/** The MSCHA pv1. */
MSCHAPv1("mschapv1"),
/** The MSCHA pv2. */
MSCHAPv2("mschapv2"),
/** The pap. */
PAP("pap"),
/** The peap. */
PEAP("peap");
/** The name. */
private final String name;
/**
* Instantiates a new radius protocol.
*
* @param name the name
*/
RadiusProtocol(final String name) {
this.name = name;
}
/**
* Gets the radius protocol name required by {@link net.jradius.client.RadiusClient#getAuthProtocol(String)}.
*
* @return RADIUS protocol name known to {@link net.jradius.client.RadiusClient}.
*/
public String getName() {
return this.name;
}
}
@@ -0,0 +1,231 @@
package org.maxkey.authn.realm.radius;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import net.jradius.client.RadiusClient;
import net.jradius.dictionary.Attr_NASIPAddress;
import net.jradius.dictionary.Attr_NASIPv6Address;
import net.jradius.dictionary.Attr_NASIdentifier;
import net.jradius.dictionary.Attr_NASPort;
import net.jradius.dictionary.Attr_NASPortId;
import net.jradius.dictionary.Attr_NASPortType;
import net.jradius.dictionary.Attr_ReplyMessage;
import net.jradius.dictionary.Attr_UserName;
import net.jradius.dictionary.Attr_UserPassword;
import net.jradius.dictionary.vsa_redback.Attr_NASRealPort;
import net.jradius.packet.AccessAccept;
import net.jradius.packet.AccessRequest;
import net.jradius.packet.RadiusPacket;
import net.jradius.packet.attribute.AttributeList;
import org.apache.commons.lang.StringUtils;
import org.maxkey.authn.realm.IAuthenticationServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Implementation of a RadiusServer that utilizes the JRadius packages available
* at <a href="http://jradius.sf.net">http://jradius.sf.net</a>.
*
*/
public final class RadiusServer extends RadiusServerBase implements IAuthenticationServer{
/** Default retry count, {@value}. */
public static final int DEFAULT_RETRY_COUNT = 3;
/** Logger instance. */
private static final Logger _logger = LoggerFactory.getLogger(RadiusServer.class);
/** RADIUS protocol. */
@NotNull
private final RadiusProtocol protocol;
/** Number of times to retry authentication when no response is received. */
@Min(0)
private int retries = DEFAULT_RETRY_COUNT;
private String nasIpAddress = null;
private String nasIpv6Address = null;
private long nasPort = -1;
private long nasPortId = -1;
private long nasIdentifier = -1;
private long nasRealPort = -1;
private long nasPortType = -1;
/**
* Instantiates a new server implementation
* with the radius protocol and client factory specified.
*
* @param protocol the protocol
* @param clientFactory the client factory
*/
public RadiusServer(final RadiusProtocol protocol) {
this.protocol = protocol;
}
public boolean authenticate(final String username, final String password) {
final AttributeList attributeList = new AttributeList();
attributeList.add(new Attr_UserName(username));
attributeList.add(new Attr_UserPassword(password));
if (StringUtils.isNotBlank(this.nasIpAddress)) {
attributeList.add(new Attr_NASIPAddress(this.nasIpAddress));
}
if (StringUtils.isNotBlank(this.nasIpv6Address)) {
attributeList.add(new Attr_NASIPv6Address(this.nasIpv6Address));
}
if (this.nasPort != -1) {
attributeList.add(new Attr_NASPort(this.nasPort));
}
if (this.nasPortId != -1) {
attributeList.add(new Attr_NASPortId(this.nasPortId));
}
if (this.nasIdentifier != -1) {
attributeList.add(new Attr_NASIdentifier(this.nasIdentifier));
}
if (this.nasRealPort != -1) {
attributeList.add(new Attr_NASRealPort(this.nasRealPort));
}
if (this.nasPortType != -1) {
attributeList.add(new Attr_NASPortType(this.nasPortType));
}
RadiusClient client = null;
try {
client = this.newInstance();
final AccessRequest request = new AccessRequest(client, attributeList);
final RadiusPacket response = client.authenticate(
request,
RadiusClient.getAuthProtocol(this.protocol.getName()),
this.retries);
_logger.debug("RADIUS response from {}: {}", client.getRemoteInetAddress().getCanonicalHostName(),response.getClass().getName());
_logger.debug("Received : \n" + response.toString());
_logger.debug("RADIUS Response Identifier : " + response.getIdentifier());
_logger.debug("RADIUS Response code : " + response.getCode());
_logger.debug("RADIUS Response AttributeList : " + response.getAttributes().getAttributeList());
if (response instanceof AccessAccept) {
// final AccessAccept acceptedResponse = (AccessAccept) response;
// _logger.debug("Accepted Response Message: " + acceptedResponse.CODE);
String responseMessage = (String) response.getAttributeValue(Attr_ReplyMessage.TYPE);
if (responseMessage != null){
_logger.debug("Accepted Response Message: " + responseMessage);
}
return true;
}else if(response instanceof net.jradius.packet.AccessReject){
_logger.debug("Access Reject ." );
}else if (response instanceof net.jradius.packet.PasswordReject){
_logger.debug("Password Reject . ");
}
} catch (final Exception e) {
e.printStackTrace();
} finally {
if (client != null) {
client.close();
}
}
return false;
}
/**
* Sets the nas ip address.
*
* @param nasIpAddress the new nas ip address
* @since 4.1
*/
public void setNasIpAddress(final String nasIpAddress) {
this.nasIpAddress = nasIpAddress;
}
/**
* Sets the nas ipv6 address.
*
* @param nasIpv6Address the new nas ipv6 address
* @since 4.1
*/
public void setNasIpv6Address(final String nasIpv6Address) {
this.nasIpv6Address = nasIpv6Address;
}
/**
* Sets the nas port.
*
* @param nasPort the new nas port
* @since 4.1
*/
public void setNasPort(final long nasPort) {
this.nasPort = nasPort;
}
/**
* Sets the nas port id.
*
* @param nasPortId the new nas port id
* @since 4.1
*/
public void setNasPortId(final long nasPortId) {
this.nasPortId = nasPortId;
}
/**
* Sets the nas identifier.
*
* @param nasIdentifier the new nas identifier
* @since 4.1
*/
public void setNasIdentifier(final long nasIdentifier) {
this.nasIdentifier = nasIdentifier;
}
/**
* Sets the nas real port.
*
* @param nasRealPort the new nas real port
* @since 4.1
*/
public void setNasRealPort(final long nasRealPort) {
this.nasRealPort = nasRealPort;
}
/**
* Sets the nas port type.
*
* @param nasPortType the new nas port type
* @since 4.1
*/
public void setNasPortType(final long nasPortType) {
this.nasPortType = nasPortType;
}
/**
* Sets the retries.
*
* @param retries the new retries
* @since 4.1
*/
public void setRetries(final int retries) {
this.retries = retries;
}
}
@@ -0,0 +1,62 @@
package org.maxkey.authn.realm.radius;
import java.util.List;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import net.jradius.packet.attribute.AttributeFactory;
import org.maxkey.authn.realm.AbstractAuthenticationRealm;
import org.maxkey.authn.realm.IAuthenticationServer;
import org.maxkey.domain.UserInfo;
import org.maxkey.web.WebContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.BadCredentialsException;
public class RadiusServerAuthenticationRealm extends AbstractAuthenticationRealm{
private final static Logger _logger = LoggerFactory.getLogger(RadiusServerAuthenticationRealm.class);
/** Load the dictionary implementation. */
static {
AttributeFactory.loadAttributeDictionary("net.jradius.dictionary.AttributeDictionaryImpl");
}
/** Array of RADIUS servers to authenticate against. */
@NotNull
@Size(min=1)
private List<IAuthenticationServer> jradiusServers;
/**
* @param ldapCluster
*/
public RadiusServerAuthenticationRealm() {
}
@Override
public boolean passwordMatches(UserInfo userInfo, String password) {
boolean isAuthenticated=false;
for (final IAuthenticationServer radiusServer : this.jradiusServers) {
_logger.debug("Attempting to authenticate {} at {}", userInfo.getUsername(), radiusServer);
isAuthenticated= radiusServer.authenticate(userInfo.getUsername(), password);
if (isAuthenticated ) {
return true;
}
}
if(!isAuthenticated){
throw new BadCredentialsException(WebContext.getI18nValue("login.error.password"));
}
return false;
}
public void setJradiusServers(List<IAuthenticationServer> jradiusServers) {
this.jradiusServers = jradiusServers;
}
}
@@ -0,0 +1,98 @@
package org.maxkey.authn.realm.radius;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import net.jradius.client.RadiusClient;
/**
* Factory for creating RADIUS client instances.
*
*/
public class RadiusServerBase {
/** The port to do accounting on. */
@Min(1)
private int accountingPort =1813;
/** The port to do authentication on. */
@Min(1)
private int authenticationPort = 1812;
/** Socket timeout in seconds. */
@Min(0)
private int socketTimeout = 30;
/** RADIUS server network address. */
@NotNull
private InetAddress inetAddress;
/** The shared secret to send to the RADIUS server. */
@NotNull
private String sharedSecret;
/**
* Sets the RADIUS server accounting port.
*
* @param port Accounting port number.
*/
public void setAccountingPort(final int port) {
this.accountingPort = port;
}
/**
* Sets the RADIUS server authentication port.
*
* @param port Authentication port number.
*/
public void setAuthenticationPort(final int port) {
this.authenticationPort = port;
}
/**
* Sets the RADIUS server UDP socket timeout.
*
* @param timeout Timeout in seconds; 0 for no timeout.
*/
public void setSocketTimeout(final int timeout) {
this.socketTimeout = timeout;
}
/**
* RADIUS server network address.
*
* @param address Network address as a string.
*/
public void setInetAddress(final String address) {
try {
this.inetAddress = InetAddress.getByName(address);
} catch (final UnknownHostException e) {
throw new RuntimeException("Invalid address " + address);
}
}
/**
* RADIUS server authentication shared secret.
*
* @param secret Shared secret.
*/
public void setSharedSecret(final String secret) {
this.sharedSecret = secret;
}
/**
* Creates a new RADIUS client instance using factory configuration settings.
*
* @return New radius client instance.
* @throws IOException In case the transport method encounters an error.
*/
public RadiusClient newInstance() throws IOException {
return new RadiusClient(
this.inetAddress, this.sharedSecret, this.authenticationPort, this.accountingPort, this.socketTimeout);
}
}
@@ -0,0 +1,118 @@
package org.maxkey.authn.support.basic;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.maxkey.constants.LOGINTYPE;
import org.maxkey.util.AuthorizationHeaderUtils;
import org.maxkey.web.WebContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
public class BasicEntryPoint extends HandlerInterceptorAdapter {
private static final Logger _logger = LoggerFactory.getLogger(BasicEntryPoint.class);
boolean enable;
String []skipRequestURI={
"/oauth/v20/token",
"/oauth/v10a/request_token",
"/oauth/v10a/access_token"
};
@Override
public boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception {
if(!enable){
return true;
}
String requestPath=request.getServletPath();
_logger.debug("HttpHeader Login Start ...");
_logger.info("Request url : "+ request.getRequestURL());
_logger.info("Request URI : "+ request.getRequestURI());
_logger.info("Request ContextPath : "+ request.getContextPath());
_logger.info("Request ServletPath : "+ request.getServletPath());
_logger.debug("RequestSessionId : "+ request.getRequestedSessionId());
_logger.debug("isRequestedSessionIdValid : "+ request.isRequestedSessionIdValid());
_logger.debug("getSession : "+ request.getSession(false));
for(int i=0;i<skipRequestURI.length;i++){
if(skipRequestURI[i].indexOf(requestPath)>-1){
_logger.info("skip uri : "+ requestPath);
return true;
}
}
// session not exists,session timeout,recreate new session
if(request.getSession(false) == null) {
request.getSession(true);
}
String basicCredential =request.getHeader(AuthorizationHeaderUtils.AUTHORIZATION_HEADERNAME);
_logger.info("getSession.getId : "+ request.getSession().getId());
_logger.info("Authorization : " + basicCredential);
if(basicCredential==null||basicCredential.equals("")){
_logger.info("Authentication fail header Authorization is null . ");
return false;
}
String username=null;
String password=null;
if(AuthorizationHeaderUtils.isBasic(basicCredential)){
String []usernamePassword=AuthorizationHeaderUtils.resolveBasic(basicCredential);
username=usernamePassword[0];
password=usernamePassword[1];
}else{
return false;
}
if(username==null||username.equals("")){
_logger.info("Authentication fail username is null . ");
return false;
}
if(password==null||password.equals("")){
_logger.info("Authentication fail password is null . ");
return false;
}
boolean isAuthenticated=false;
if(SecurityContextHolder.getContext().getAuthentication() == null) {
_logger.info("Security Authentication is null .");
isAuthenticated=false;
}else {
_logger.info("Security Authentication not null . ");
UsernamePasswordAuthenticationToken authenticationToken = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
String lastSessionUserName = authenticationToken.getPrincipal().toString();
_logger.info("Authentication Principal : " + lastSessionUserName);
if (lastSessionUserName != null && !lastSessionUserName.equals(username)) {
isAuthenticated=false;
}else{
isAuthenticated=true;
}
}
if(!isAuthenticated){
if(WebContext.setAuthentication(username,LOGINTYPE.BASIC,"","","success")){
_logger.info("Authentication "+username+" successful .");
}
}
return true;
}
/**
* @param enable the enable to set
*/
public void setEnable(boolean enable) {
this.enable = enable;
}
}
@@ -0,0 +1,57 @@
package org.maxkey.authn.support.cas;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jasig.cas.client.util.AbstractCasFilter;
import org.jasig.cas.client.validation.Assertion;
import org.maxkey.config.ApplicationConfig;
import org.maxkey.constants.LOGINTYPE;
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.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* @author Crystal.Sea
*
*/
@Controller
public class CasEndpoint {
private static Logger _logger = LoggerFactory.getLogger(CasEndpoint.class);
@Autowired
@Qualifier("applicationConfig")
protected ApplicationConfig applicationConfig;
/**
* init login
* @return
*/
@RequestMapping(value={"/logon/cas"})
public ModelAndView casLogin(
HttpServletRequest request,
HttpServletResponse response) {
_logger.debug("CasEndpoint /cas.");
Assertion assertion = (Assertion) request.getSession().getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION);
String username= assertion.getPrincipal().getName();
_logger.debug("CAS username : "+username);
if(WebContext.setAuthentication(username,LOGINTYPE.CAS,"","","success")){
}
return WebContext.redirect("/login");
}
}
@@ -0,0 +1,27 @@
package org.maxkey.authn.support.cas;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
public class CasEntryPoint implements AuthenticationEntryPoint {
private static final Logger _logger = LoggerFactory.getLogger(CasEntryPoint.class);
/* (non-Javadoc)
* @see org.springframework.security.web.AuthenticationEntryPoint#commence(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.springframework.security.core.AuthenticationException)
*/
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException ex) throws IOException, ServletException {
_logger.debug("CasEntryPoint..");
}
}
@@ -0,0 +1,28 @@
package org.maxkey.authn.support.httpheader;
public class HttpHeaderConfig {
String headerName;
boolean enable;
/**
*
*/
public HttpHeaderConfig() {
}
public String getHeaderName() {
return headerName;
}
public void setHeaderName(String headerName) {
this.headerName = headerName;
}
public boolean isEnable() {
return enable;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
}
@@ -0,0 +1,101 @@
package org.maxkey.authn.support.httpheader;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.maxkey.constants.LOGINTYPE;
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.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
public class HttpHeaderEntryPoint extends HandlerInterceptorAdapter {
private static final Logger _logger = LoggerFactory.getLogger(HttpHeaderEntryPoint.class);
@Autowired
@Qualifier("httpHeaderSupport")
HttpHeaderConfig httpHeaderSupport;
String []skipRequestURI={
"/oauth/v20/token",
"/oauth/v10a/request_token",
"/oauth/v10a/access_token"
};
@Override
public boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception {
if(!httpHeaderSupport.isEnable()){
return true;
}
String requestPath=request.getServletPath();
_logger.debug("HttpHeader Login Start ...");
_logger.info("Request url : "+ request.getRequestURL());
_logger.info("Request URI : "+ request.getRequestURI());
_logger.info("Request ContextPath : "+ request.getContextPath());
_logger.info("Request ServletPath : "+ request.getServletPath());
_logger.debug("RequestSessionId : "+ request.getRequestedSessionId());
_logger.debug("isRequestedSessionIdValid : "+ request.isRequestedSessionIdValid());
_logger.debug("getSession : "+ request.getSession(false));
for(int i=0;i<skipRequestURI.length;i++){
if(skipRequestURI[i].indexOf(requestPath)>-1){
_logger.info("skip uri : "+ requestPath);
return true;
}
}
// session not exists,session timeout,recreate new session
if(request.getSession(false) == null) {
request.getSession(true);
}
_logger.info("getSession.getId : "+ request.getSession().getId());
String httpHeaderUsername = request.getHeader(httpHeaderSupport.getHeaderName());
_logger.info("HttpHeader username : " + httpHeaderUsername);
if(httpHeaderUsername==null||httpHeaderUsername.equals("")){
_logger.info("Authentication fail HttpHeader is null . ");
return false;
}
boolean isAuthenticated=false;
if(SecurityContextHolder.getContext().getAuthentication() == null) {
_logger.info("Security Authentication is null .");
isAuthenticated=false;
}else {
_logger.info("Security Authentication not null . ");
UsernamePasswordAuthenticationToken authenticationToken = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
String lastSessionUserName = authenticationToken.getPrincipal().toString();
_logger.info("Authentication Principal : " + lastSessionUserName);
if (lastSessionUserName != null && !lastSessionUserName.equals(httpHeaderUsername)) {
isAuthenticated=false;
}else{
isAuthenticated=true;
}
}
if(!isAuthenticated){
if(WebContext.setAuthentication(httpHeaderUsername,LOGINTYPE.HTTPHEADER,"","","success")){
_logger.info("Authentication "+httpHeaderUsername+" successful .");
}
}
return true;
}
public void setHttpHeaderSupport(HttpHeaderConfig httpHeaderSupport) {
this.httpHeaderSupport = httpHeaderSupport;
}
}
@@ -0,0 +1,63 @@
package org.maxkey.authn.support.kerberos;
public class KerberosProxy {
String userdomain;
String fullUserdomain;
String crypto;
String redirectUri;
/**
*
*/
public KerberosProxy() {
super();
}
public String getUserdomain() {
return userdomain;
}
public void setUserdomain(String userdomain) {
this.userdomain = userdomain.toUpperCase();
}
public String getFullUserdomain() {
return fullUserdomain;
}
public void setFullUserdomain(String fullUserdomain) {
this.fullUserdomain = fullUserdomain.toUpperCase();
}
public String getCrypto() {
return crypto;
}
public void setCrypto(String crypto) {
this.crypto = crypto;
}
public String getRedirectUri() {
return redirectUri;
}
public void setRedirectUri(String redirectUri) {
this.redirectUri = redirectUri;
}
@Override
public String toString() {
return "KerberosProxy [userdomain=" + userdomain + ", fullUserdomain="
+ fullUserdomain + ", crypto=" + crypto
+ ", redirectUri=" + redirectUri + "]";
}
}
@@ -0,0 +1,9 @@
package org.maxkey.authn.support.kerberos;
public interface KerberosService {
public boolean login(String kerberosTokenString,String kerberosUserDomain);
public String buildKerberosProxys( );
}
@@ -0,0 +1,60 @@
package org.maxkey.authn.support.kerberos;
public class KerberosToken {
private String principal;
private String fullPrincipal;
private String notOnOrAfter;
private String userDomain;
/**
*
*/
public KerberosToken() {
super();
}
public String getPrincipal() {
return principal;
}
public void setPrincipal(String principal) {
this.principal = principal;
}
public String getFullPrincipal() {
return fullPrincipal;
}
public void setFullPrincipal(String fullPrincipal) {
this.fullPrincipal = fullPrincipal;
}
public String getNotOnOrAfter() {
return notOnOrAfter;
}
public void setNotOnOrAfter(String notOnOrAfter) {
this.notOnOrAfter = notOnOrAfter;
}
public String getUserDomain() {
return userDomain;
}
public void setUserDomain(String userDomain) {
this.userDomain = userDomain;
}
@Override
public String toString() {
return "KerberosToken [principal=" + principal + ", fullPrincipal="
+ fullPrincipal + ", notOnOrAfter=" + notOnOrAfter
+ ", userDomain=" + userDomain + "]";
}
}
@@ -0,0 +1,69 @@
package org.maxkey.authn.support.kerberos;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.joda.time.DateTime;
import org.maxkey.constants.LOGINTYPE;
import org.maxkey.crypto.ReciprocalUtils;
import org.maxkey.util.DateUtils;
import org.maxkey.util.JsonUtils;
import org.maxkey.web.WebContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RemoteKerberosService implements KerberosService{
private static Logger _logger = LoggerFactory.getLogger(RemoteKerberosService.class);
List<KerberosProxy> kerberosProxys;
public boolean login(String kerberosTokenString,String kerberosUserDomain){
_logger.debug("encoder Kerberos Token "+kerberosTokenString);
_logger.debug("kerberos UserDomain "+kerberosUserDomain);
String decoderKerberosToken=null;
for(KerberosProxy kerberosProxy : kerberosProxys){
if(kerberosProxy.getUserdomain().equalsIgnoreCase(kerberosUserDomain)){
decoderKerberosToken=ReciprocalUtils.aesDecoder(kerberosTokenString, kerberosProxy.getCrypto());
break;
}
}
_logger.debug("decoder Kerberos Token "+decoderKerberosToken);
KerberosToken kerberosToken=new KerberosToken();
kerberosToken=(KerberosToken)JsonUtils.json2Object(decoderKerberosToken, kerberosToken);
_logger.debug("Kerberos Token "+kerberosToken);
DateTime notOnOrAfter=DateUtils.toUtcDate(kerberosToken.getNotOnOrAfter());
_logger.debug("Kerberos Token is After Now "+notOnOrAfter.isAfterNow());
if(notOnOrAfter.isAfterNow()){
return WebContext.setAuthentication(kerberosToken.getPrincipal(),LOGINTYPE.KERBEROS,kerberosUserDomain,"","success");
}else{
return false;
}
}
public List<KerberosProxy> getKerberosProxys() {
return kerberosProxys;
}
public void setKerberosProxys(List<KerberosProxy> kerberosProxys) {
this.kerberosProxys = kerberosProxys;
}
public String buildKerberosProxys(){
List<Map<String,String>>userDomainUrlList=new ArrayList<Map<String,String>>();
for (KerberosProxy kerberosProxy :kerberosProxys){
Map<String,String> userDomainUrl =new HashMap<String,String>();
userDomainUrl.put("userDomain", kerberosProxy.getUserdomain());
userDomainUrl.put("redirectUri", kerberosProxy.getRedirectUri());
userDomainUrlList.add(userDomainUrl);
}
_logger.debug(""+userDomainUrlList);
String userDomainUrlJson=JsonUtils.object2Json(userDomainUrlList);
_logger.debug("userDomain Url Json "+userDomainUrlJson);
return userDomainUrlJson;
}
}
@@ -0,0 +1,167 @@
/**
*
*/
package org.maxkey.authn.support.socialsignon;
import java.util.HashMap;
import java.util.Map;
import org.maxkey.authn.support.socialsignon.service.SocialSignOnProvider;
import org.maxkey.authn.support.socialsignon.service.SocialSignOnProviderService;
import org.maxkey.authn.support.socialsignon.service.SocialSignOnUserTokenService;
import org.maxkey.client.http.HttpVerb;
import org.maxkey.client.http.Response;
import org.maxkey.client.oauth.model.OAuthRequest;
import org.maxkey.client.oauth.model.Token;
import org.maxkey.client.oauth.model.Verifier;
import org.maxkey.client.oauth.oauth.OAuthService;
import org.maxkey.util.JsonUtils;
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;
/**
* @author Crystal.Sea
*
*/
public class AbstractSocialSignOnEndpoint {
final static Logger _logger = LoggerFactory.getLogger(AbstractSocialSignOnEndpoint.class);
protected final static String SOCIALSIGNON_SESSION_REDIRECT_URI="socialsignon_session_redirect_uri";
protected final static String SOCIALSIGNON_REDIRECT_URI="redirect_uri";
public final static String SOCIALSIGNON_TYPE_SESSION="socialsignon_type_session";
public final static String SOCIALSIGNON_OAUTH_SERVICE_SESSION="socialsignon_oauth_service_session";
public final static String SOCIALSIGNON_PROVIDER_SESSION="socialsignon_provider_session";
public final static class SOCIALSIGNON_TYPE{
public final static String SOCIALSIGNON_TYPE_LOGON="socialsignon_type_logon";
public final static String SOCIALSIGNON_TYPE_BIND="socialsignon_type_bind";
}
protected Token accessToken;
protected SocialSignOnProvider socialSignOnProvider;
protected OAuthService oauthService;
protected String accountJsonString;
protected String accountId;
protected String provider;
@Autowired
protected SocialSignOnProviderService socialSignOnProviderService;
@Autowired
protected SocialSignOnUserTokenService socialSignOnUserTokenService;
protected OAuthService buildOAuthService(String provider){
SocialSignOnProvider socialSignOnProvider = socialSignOnProviderService.get(provider);
_logger.debug("socialSignOn Provider : "+socialSignOnProvider);
if(socialSignOnProvider!=null){
OAuthServiceBuilder oAuthServiceBuilder=new OAuthServiceBuilder(socialSignOnProvider);
oauthService=oAuthServiceBuilder.builderOAuthService();
WebContext.setAttribute(SOCIALSIGNON_OAUTH_SERVICE_SESSION, socialSignOnProvider);
WebContext.setAttribute(SOCIALSIGNON_PROVIDER_SESSION, oauthService);
return oauthService;
}
return null;
}
/**
* get accessToken
* @param service
* @return
*/
protected Token getAccessToken() {
socialSignOnProvider=(SocialSignOnProvider)WebContext.getAttribute(SOCIALSIGNON_OAUTH_SERVICE_SESSION);
oauthService=(OAuthService)WebContext.getAttribute(SOCIALSIGNON_PROVIDER_SESSION);
String oauthVerifier = WebContext.getRequest().getParameter(socialSignOnProvider.getVerifierCode());
WebContext.removeAttribute(SOCIALSIGNON_OAUTH_SERVICE_SESSION);
WebContext.removeAttribute(SOCIALSIGNON_PROVIDER_SESSION);
if(StringUtils.isNullOrBlank(socialSignOnProvider.getVerifierCode()))
return null;
// getting access token
Verifier verifier = new Verifier(oauthVerifier);
this.accessToken=oauthService.getAccessToken(null, verifier);
return accessToken;
}
protected String requestAccountJson() {
OAuthRequest oauthRequest = new OAuthRequest(HttpVerb.GET, this.convertAccountUrl(socialSignOnProvider.getAccountUrl(),socialSignOnProvider.getProvider(), accessToken));
oauthService.signRequest(accessToken, oauthRequest);
Response oauthResponse = oauthRequest.send();
accountJsonString=oauthResponse.getBody();
_logger.debug("requestAccountJson : "+accountJsonString);
return accountJsonString;
}
@SuppressWarnings("unchecked")
protected String getAccountId() {
//if(StringUtils.isNullOrBlank(accountJsonString)) {
requestAccountJson();
//}
if(this.provider.equals("qq")){
accountJsonString=accountJsonString.substring(accountJsonString.indexOf("{"), accountJsonString.indexOf("}")+1);
}
Map<String,Object> map = new HashMap<String,Object>();
map=(HashMap<String,Object>)JsonUtils.json2Object(accountJsonString, map);
if(this.provider.equals("qqweibo")){
if(accessToken.getResponseObject().get(socialSignOnProvider.getAccountId())!=null){
accountId=accessToken.getResponseObject().get(socialSignOnProvider.getAccountId()).toString();
}
}else if(this.provider.equals("qq")){
accountId=map.get(socialSignOnProvider.getAccountId()).toString();
}else{
if(map.get(socialSignOnProvider.getAccountId())!=null){
accountId=map.get(socialSignOnProvider.getAccountId()).toString();
}
}
_logger.debug("getAccountId : "+accountId);
return accountId;
}
private String convertAccountUrl(String accountUrl,String provider,Token accessToken) {
if("sinaweibo".equals(provider)) {
if(null!=accessToken.getResponseObject()) {
Object uid = accessToken.getResponseObject().get("uid");
accountUrl = this.convertUrl(accountUrl, "uid", uid == null ? "" : uid.toString());
}
}
return accountUrl;
}
private String convertUrl(String url,String paramName,String paramVal) {
StringBuilder sb = new StringBuilder(url);
if (url.indexOf('?') < 0) {
sb.append('?');
}
else {
sb.append('&');
}
sb.append(paramName+"=").append(paramVal);
return sb.toString();
}
}
@@ -0,0 +1,91 @@
package org.maxkey.authn.support.socialsignon;
import org.maxkey.authn.support.socialsignon.service.SocialSignOnProvider;
import org.maxkey.client.http.SignatureType;
import org.maxkey.client.oauth.builder.ServiceBuilder;
import org.maxkey.client.oauth.builder.api.Api;
import org.maxkey.client.oauth.builder.api.OAuthApi20;
import org.maxkey.client.oauth.oauth.OAuthService;
import org.maxkey.web.WebContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class OAuthServiceBuilder {
private static Logger _logger = LoggerFactory.getLogger(OAuthServiceBuilder.class);
private SocialSignOnProvider socialSignOnProvider;
private Api api;
/**
*
*/
public OAuthServiceBuilder() {
}
/**
* @param socialSignOnProvider
*/
public OAuthServiceBuilder(SocialSignOnProvider socialSignOnProvider) {
this.socialSignOnProvider = socialSignOnProvider;
String callbackUrl=WebContext.getHttpContextPath()+ "/logon/oauth20/callback/"+socialSignOnProvider.getProvider();
socialSignOnProvider.setCallBack(callbackUrl);
api = new OAuthApi20(socialSignOnProvider.getAuthorizeUrl(),
socialSignOnProvider.getAccessTokenUrl(),
socialSignOnProvider.getAccessTokenMethod());
_logger.debug("api : "+api);
}
public OAuthService builderOAuthService() {
if(socialSignOnProvider.getScope()==null||socialSignOnProvider.getScope().equals("")){
return new ServiceBuilder().provider(api)
.apiKey(socialSignOnProvider.getClientId())
.apiSecret(socialSignOnProvider.getClientSecret())
.callback(socialSignOnProvider.getCallBack())
.signatureType(SignatureType.QueryString)
.debug()
.build();
}else{
return new ServiceBuilder().provider(api)
.apiKey(socialSignOnProvider.getClientId())
.apiSecret(socialSignOnProvider.getClientSecret())
.scope(socialSignOnProvider.getScope())
.callback(socialSignOnProvider.getCallBack())
.signatureType(SignatureType.QueryString)
.debug()
.build();
}
}
public SocialSignOnProvider getSocialSignOnProvider() {
return socialSignOnProvider;
}
public void setSocialSignOnProvider(SocialSignOnProvider socialSignOnProvider) {
this.socialSignOnProvider = socialSignOnProvider;
}
public Api getApi() {
return api;
}
public void setApi(Api api) {
this.api = api;
}
}
@@ -0,0 +1,154 @@
/**
*
*/
package org.maxkey.authn.support.socialsignon;
import javax.servlet.http.HttpServletRequest;
import org.maxkey.authn.realm.AbstractAuthenticationRealm;
import org.maxkey.authn.support.socialsignon.service.SocialSignOnUserToken;
import org.maxkey.constants.LOGINTYPE;
import org.maxkey.util.JsonUtils;
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.security.authentication.BadCredentialsException;
import org.springframework.security.web.WebAttributes;
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.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
/**
* @author Crystal.Sea
*
*/
@Controller
@RequestMapping(value = "/logon/oauth20")
public class SocialSignOnEndpoint extends AbstractSocialSignOnEndpoint{
final static Logger _logger = LoggerFactory.getLogger(SocialSignOnEndpoint.class);
@Autowired
@Qualifier("authenticationRealm")
protected AbstractAuthenticationRealm authenticationRealm;
public ModelAndView socialSignOnAuthorize(String provider){
_logger.debug("SocialSignOn provider : "+provider);
String authorizationUrl=buildOAuthService(provider).getAuthorizationUrl(null);
_logger.debug("authorize SocialSignOn : "+authorizationUrl);
return WebContext.redirect(authorizationUrl);
}
@RequestMapping(value={"/authorize/{provider}"}, method = RequestMethod.GET)
public ModelAndView authorize(@PathVariable String provider) {
WebContext.setAttribute(SOCIALSIGNON_TYPE_SESSION, SOCIALSIGNON_TYPE.SOCIALSIGNON_TYPE_LOGON);
return socialSignOnAuthorize(provider);
}
@RequestMapping(value={"/bind/{provider}"}, method = RequestMethod.GET)
public ModelAndView bind(HttpServletRequest request,
@PathVariable String provider) {
WebContext.setAttribute(SOCIALSIGNON_SESSION_REDIRECT_URI, request.getParameter(SOCIALSIGNON_REDIRECT_URI));
WebContext.setAttribute(SOCIALSIGNON_TYPE_SESSION, SOCIALSIGNON_TYPE.SOCIALSIGNON_TYPE_BIND);
return socialSignOnAuthorize(provider);
}
@RequestMapping(value={"/unbind/{provider}"}, method = RequestMethod.GET)
public ModelAndView unbind(HttpServletRequest request,
@PathVariable String provider) {
WebContext.setAttribute(SOCIALSIGNON_SESSION_REDIRECT_URI, request.getParameter(SOCIALSIGNON_REDIRECT_URI));
SocialSignOnUserToken socialSignOnUser =new SocialSignOnUserToken();
socialSignOnUser.setProvider(provider);
socialSignOnUser.setUid(WebContext.getUserInfo().getId());
socialSignOnUser.setUsername(WebContext.getUserInfo().getUsername());
_logger.debug("Social Sign On unbind "+provider+" from user "+WebContext.getUserInfo().getUsername());
socialSignOnUserTokenService.delete(socialSignOnUser);
if(WebContext.getAttribute(SOCIALSIGNON_SESSION_REDIRECT_URI)!=null){
return WebContext.redirect(WebContext.getAttribute(SOCIALSIGNON_SESSION_REDIRECT_URI).toString());
}else{
return WebContext.forward("/socialsignon/list");
}
}
@RequestMapping(value={"/authorize/{provider}/{appid}"}, method = RequestMethod.GET)
public ModelAndView authorize2AppId(@PathVariable("provider") String provider,
@PathVariable("appid") String appid) {
WebContext.setAttribute(SOCIALSIGNON_SESSION_REDIRECT_URI, "/authorize/"+appid);
return authorize(provider);
}
@RequestMapping(value={"/callback/{provider}"}, method = RequestMethod.GET)
public ModelAndView callback(@PathVariable String provider
) {
this.provider=provider;
this.getAccessToken();
this.getAccountId();
_logger.debug(this.accountId);
SocialSignOnUserToken socialSignOnUserToken =new SocialSignOnUserToken();
socialSignOnUserToken.setProvider(provider);
socialSignOnUserToken.setSocialuid(this.accountId);
//for login
String socialSignOnType= "";
if(WebContext.getAttribute(SOCIALSIGNON_TYPE_SESSION)!=null){
socialSignOnType=WebContext.getAttribute(SOCIALSIGNON_TYPE_SESSION).toString();
}
if(socialSignOnType.equals(SOCIALSIGNON_TYPE.SOCIALSIGNON_TYPE_LOGON)||socialSignOnType.equals("")){
socialSignOn(socialSignOnUserToken);
return WebContext.redirect("/index");
}else{
socialBind(socialSignOnUserToken);
}
if(WebContext.getAttribute(SOCIALSIGNON_SESSION_REDIRECT_URI)!=null){
return WebContext.redirect(WebContext.getAttribute(SOCIALSIGNON_SESSION_REDIRECT_URI).toString());
}else{
return WebContext.forward("/socialsignon/list");
}
}
public boolean socialBind(SocialSignOnUserToken socialSignOnUserToken){
socialSignOnUserToken.setSocialUserInfo(accountJsonString);
socialSignOnUserToken.setUid(WebContext.getUserInfo().getId());
socialSignOnUserToken.setUsername(WebContext.getUserInfo().getUsername());
socialSignOnUserToken.setAccessToken(JsonUtils.object2Json(accessToken));
socialSignOnUserToken.setExAttribute(JsonUtils.object2Json(accessToken.getResponseObject()));
_logger.debug("Social Bind : "+socialSignOnUserToken);
this.socialSignOnUserTokenService.delete(socialSignOnUserToken);
this.socialSignOnUserTokenService.insert(socialSignOnUserToken);
return true;
}
public boolean socialSignOn(SocialSignOnUserToken socialSignOnUserToken){
socialSignOnUserToken=this.socialSignOnUserTokenService.get(socialSignOnUserToken);
_logger.debug("callback SocialSignOn User Token : "+socialSignOnUserToken);
if(null !=socialSignOnUserToken){
_logger.debug("Social Sign On from "+socialSignOnUserToken.getProvider()+" mapping to user "+socialSignOnUserToken.getUsername());
if(WebContext.setAuthentication(socialSignOnUserToken.getUsername(), LOGINTYPE.SOCIALSIGNON,this.socialSignOnProvider.getProviderName(),"xe00000004","success")){
socialSignOnUserToken.setAccessToken(JsonUtils.object2Json(this.accessToken));
socialSignOnUserToken.setSocialUserInfo(accountJsonString);
socialSignOnUserToken.setExAttribute(JsonUtils.object2Json(accessToken.getResponseObject()));
this.socialSignOnUserTokenService.update(socialSignOnUserToken);
}
}else{
WebContext.getRequest().getSession().setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, new BadCredentialsException(WebContext.getI18nValue("login.error.social")));
}
return true;
}
}
@@ -0,0 +1,112 @@
package org.maxkey.authn.support.socialsignon.service;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Date;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
public class JdbcSocialSignOnUserTokenService implements SocialSignOnUserTokenService{
private static final Logger _logger = LoggerFactory.getLogger(JdbcSocialSignOnUserTokenService.class);
private static final String DEFAULT_DEFAULT_INSERT_STATEMENT = "INSERT INTO SOCIALSIGNON_USERS_TOKEN(ID, UID , USERNAME , PROVIDER , SOCIALUID , ACCESSTOKEN , SOCIALUSERINFO , EXATTRIBUTE )VALUES( ? , ? , ? , ? , ?, ? , ? , ?)";
private static final String DEFAULT_DEFAULT_SIGNON_SELECT_STATEMENT = "SELECT ID, UID , USERNAME , PROVIDER , SOCIALUID , ACCESSTOKEN , SOCIALUSERINFO , EXATTRIBUTE FROM SOCIALSIGNON_USERS_TOKEN WHERE PROVIDER = ? AND SOCIALUID = ?";
private static final String DEFAULT_DEFAULT_BIND_SELECT_STATEMENT = "SELECT ID, UID , USERNAME , PROVIDER , SOCIALUID , ACCESSTOKEN , SOCIALUSERINFO , EXATTRIBUTE FROM SOCIALSIGNON_USERS_TOKEN WHERE UID = ?" ;
private static final String DEFAULT_DEFAULT_DELETE_STATEMENT = "DELETE FROM SOCIALSIGNON_USERS_TOKEN WHERE UID = ? AND PROVIDER = ?";
private static final String DEFAULT_DEFAULT_UPDATE_STATEMENT= "UPDATE SOCIALSIGNON_USERS_TOKEN SET ACCESSTOKEN = ? , SOCIALUSERINFO = ? , EXATTRIBUTE = ? ,UPDATEDDATE = ? WHERE ID = ?";
private final JdbcTemplate jdbcTemplate;
public JdbcSocialSignOnUserTokenService(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate=jdbcTemplate;
}
@Override
public boolean insert(SocialSignOnUserToken socialSignOnUserToken) {
socialSignOnUserToken.setId(socialSignOnUserToken.generateId());
jdbcTemplate.update(DEFAULT_DEFAULT_INSERT_STATEMENT,
new Object[] {
socialSignOnUserToken.getId(),
socialSignOnUserToken.getUid(),
socialSignOnUserToken.getUsername(),
socialSignOnUserToken.getProvider(),
socialSignOnUserToken.getSocialuid(),
socialSignOnUserToken.getAccessToken(),
socialSignOnUserToken.getSocialUserInfo(),
socialSignOnUserToken.getExAttribute()},
new int[] {Types.VARCHAR, Types.VARCHAR,Types.VARCHAR,Types.VARCHAR, Types.VARCHAR,Types.VARCHAR, Types.VARCHAR,Types.VARCHAR });
return true;
}
@Override
public boolean delete(SocialSignOnUserToken socialSignOnUserToken) {
jdbcTemplate.update(DEFAULT_DEFAULT_DELETE_STATEMENT,
new Object[] {
socialSignOnUserToken.getUid(),
socialSignOnUserToken.getProvider()
},
new int[] {Types.VARCHAR, Types.VARCHAR});
return true;
}
@Override
public SocialSignOnUserToken get(SocialSignOnUserToken socialSignOnUserToken) {
List<SocialSignOnUserToken> listSocialSignOnUserToken=jdbcTemplate.query(
DEFAULT_DEFAULT_SIGNON_SELECT_STATEMENT,
new SocialSignOnUserTokenRowMapper(),
socialSignOnUserToken.getProvider(),
socialSignOnUserToken.getSocialuid());
_logger.debug("list SocialSignOnUserToken "+listSocialSignOnUserToken);
return (listSocialSignOnUserToken.size()>0)?listSocialSignOnUserToken.get(0):null;
}
@Override
public List<SocialSignOnUserToken> query(
SocialSignOnUserToken socialSignOnUserToken) {
List<SocialSignOnUserToken> listSocialSignOnUserToken=jdbcTemplate.query(
DEFAULT_DEFAULT_BIND_SELECT_STATEMENT,
new SocialSignOnUserTokenRowMapper(),
socialSignOnUserToken.getUid());
_logger.debug("query bind SocialSignOnUser "+listSocialSignOnUserToken);
return listSocialSignOnUserToken;
}
@Override
public boolean update(SocialSignOnUserToken socialSignOnUserToken) {
jdbcTemplate.update(DEFAULT_DEFAULT_UPDATE_STATEMENT,
new Object[] {socialSignOnUserToken.getAccessToken(),socialSignOnUserToken.getSocialUserInfo(),socialSignOnUserToken.getExAttribute(),new Date(),socialSignOnUserToken.getId()},
new int[] {Types.VARCHAR, Types.VARCHAR,Types.VARCHAR, Types.TIMESTAMP,Types.VARCHAR });
return false;
}
private final class SocialSignOnUserTokenRowMapper implements RowMapper<SocialSignOnUserToken> {
@Override
public SocialSignOnUserToken mapRow(ResultSet rs, int rowNum)
throws SQLException {
SocialSignOnUserToken socialSignOnUserToken=new SocialSignOnUserToken();
socialSignOnUserToken.setId(rs.getString(1));
socialSignOnUserToken.setUid(rs.getString(2));
socialSignOnUserToken.setUsername(rs.getString(3));
socialSignOnUserToken.setProvider(rs.getString(4));
socialSignOnUserToken.setSocialuid(rs.getString(5));
socialSignOnUserToken.setAccessToken(rs.getString(6));
socialSignOnUserToken.setSocialUserInfo(rs.getString(7));
socialSignOnUserToken.setExAttribute(rs.getString(8));
return socialSignOnUserToken;
}
}
}
@@ -0,0 +1,143 @@
package org.maxkey.authn.support.socialsignon.service;
/**
* @author Crystal.Sea
*
*/
public class SocialSignOnProvider {
private String provider;
private String providerName;
private String icon;
private String clientId;
private String clientSecret;
private String callBack;
private String authorizeUrl;
private String accessTokenUrl;
private String accessTokenMethod;
private String scope;
private String verifierCode;
private String accountUrl;
private String accountId;
private int sortOrder;
private boolean userBind;
/**
*
*/
public SocialSignOnProvider() {
}
public String getProvider() {
return provider;
}
public void setProvider(String provider) {
this.provider = provider;
}
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon;
}
public String getProviderName() {
return providerName;
}
public void setProviderName(String providerName) {
this.providerName = providerName;
}
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String getClientSecret() {
return clientSecret;
}
public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret;
}
public String getAuthorizeUrl() {
return authorizeUrl;
}
public void setAuthorizeUrl(String authorizeUrl) {
this.authorizeUrl = authorizeUrl;
}
public String getAccessTokenUrl() {
return accessTokenUrl;
}
public void setAccessTokenUrl(String accessTokenUrl) {
this.accessTokenUrl = accessTokenUrl;
}
public String getAccessTokenMethod() {
return accessTokenMethod;
}
public void setAccessTokenMethod(String accessTokenMethod) {
this.accessTokenMethod = accessTokenMethod;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
public String getVerifierCode() {
return verifierCode;
}
public void setVerifierCode(String verifierCode) {
this.verifierCode = verifierCode;
}
public String getAccountUrl() {
return accountUrl;
}
public void setAccountUrl(String accountUrl) {
this.accountUrl = accountUrl;
}
public String getAccountId() {
return accountId;
}
public void setAccountId(String accountId) {
this.accountId = accountId;
}
public int getSortOrder() {
return sortOrder;
}
public void setSortOrder(int sortOrder) {
this.sortOrder = sortOrder;
}
public String getCallBack() {
return callBack;
}
public void setCallBack(String callBack) {
this.callBack = callBack;
}
public boolean isUserBind() {
return userBind;
}
public void setUserBind(boolean userBind) {
this.userBind = userBind;
}
@Override
public String toString() {
return "SocialSignOnProvider [provider=" + provider + ", providerName="
+ providerName + ", icon=" + icon + ", clientId=" + clientId
+ ", clientSecret=" + clientSecret + ", authorizeUrl="
+ authorizeUrl + ", accessTokenUrl=" + accessTokenUrl
+ ", accessTokenMethod=" + accessTokenMethod + ", scope="
+ scope + ", verifierCode=" + verifierCode + ", accountUrl="
+ accountUrl + ", accountId=" + accountId + ", sortOrder="
+ sortOrder + ", userBind=" + userBind + "]";
}
}
@@ -0,0 +1,39 @@
package org.maxkey.authn.support.socialsignon.service;
import java.util.HashMap;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SocialSignOnProviderService{
private static Logger _logger = LoggerFactory.getLogger(SocialSignOnProviderService.class);
List<SocialSignOnProvider> socialSignOnProviders;
HashMap<String ,SocialSignOnProvider>socialSignOnProviderMaps=new HashMap<String ,SocialSignOnProvider>();
public SocialSignOnProvider get(String provider){
return socialSignOnProviderMaps.get(provider);
}
public List<SocialSignOnProvider> getSocialSignOnProviders() {
return socialSignOnProviders;
}
public void setSocialSignOnProviders(
List<SocialSignOnProvider> socialSignOnProviders) {
this.socialSignOnProviders = socialSignOnProviders;
for(SocialSignOnProvider socialSignOnProvider : socialSignOnProviders){
socialSignOnProviderMaps.put(socialSignOnProvider.getProvider(), socialSignOnProvider);
}
_logger.debug(""+socialSignOnProviders);
}
}
@@ -0,0 +1,103 @@
package org.maxkey.authn.support.socialsignon.service;
import org.apache.mybatis.jpa.persistence.JpaBaseDomain;
/**
*
* @author Crystal.Sea
*/
public class SocialSignOnUserToken extends JpaBaseDomain {
/**
*
*/
private static final long serialVersionUID = 2151179554190800162L;
private String id;
private String provider;
private String uid;
private String username;
private String socialuid;
private String socialUserInfo;
private String accessToken;
private String exAttribute;
public SocialSignOnUserToken() {}
/**
* @return the id
*/
public String getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(String id) {
this.id = id;
}
public String getProvider() {
return provider;
}
public void setProvider(String provider) {
this.provider = provider;
}
public String getUid() {
return uid;
}
public void setUid(String uid) {
this.uid = uid;
}
public String getSocialuid() {
return socialuid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public void setSocialuid(String socialuid) {
this.socialuid = socialuid;
}
public String getSocialUserInfo() {
return socialUserInfo;
}
public void setSocialUserInfo(String socialUserInfo) {
this.socialUserInfo = socialUserInfo;
}
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public String getExAttribute() {
return exAttribute;
}
public void setExAttribute(String exAttribute) {
this.exAttribute = exAttribute;
}
@Override
public String toString() {
return "SocialSignOnUserToken [provider=" + provider + ", uid=" + uid
+ ", socialuid=" + socialuid + ", socialUserInfo="
+ socialUserInfo + ", accessToken=" + accessToken
+ ", exAttribute=" + exAttribute + "]";
}
}
@@ -0,0 +1,18 @@
package org.maxkey.authn.support.socialsignon.service;
import java.util.List;
public interface SocialSignOnUserTokenService{
public boolean insert(SocialSignOnUserToken socialSignOnUserToken);
public List<SocialSignOnUserToken> query (SocialSignOnUserToken socialSignOnUserToken);
public SocialSignOnUserToken get (SocialSignOnUserToken socialSignOnUserToken);
public boolean delete (SocialSignOnUserToken socialSignOnUserToken);
public boolean update (SocialSignOnUserToken socialSignOnUserToken);
}
@@ -0,0 +1,39 @@
package org.maxkey.authn.support.wsfederation;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This will remove the @example.org from the upn local accounts. Other IdP should
* have the upn un-altered to prevent users collusions in CAS-based applications.
*
*/
public class WsFedAttributeMutatorImpl implements WsFederationAttributeMutator {
private static final Logger _logger = LoggerFactory.getLogger(WsFedAttributeMutatorImpl.class);
@Override
public void modifyAttributes(Map<String, Object> attributes,String upnSuffix) {
if ( attributes.containsKey("upn") ) {
attributes.put("upn", attributes.get("upn").toString().replace("@"+upnSuffix, ""));
_logger.debug(String.format("modifyAttributes: upn modified (%s)", attributes.get("upn").toString()));
}else {
_logger.warn("modifyAttributes: upn attribute not found");
}
attributeMapping(attributes, "surname", "LastName");
attributeMapping(attributes, "givenname", "FirstName");
attributeMapping(attributes, "Group", "Groups");
attributeMapping(attributes, "employeeNumber", "UDC_IDENTIFIER");
}
private void attributeMapping(Map<String, Object> attributes, String oldName, String newName) {
if ( attributes.containsKey(oldName) ) {
_logger.debug(String.format("attributeRemapping: %s -> %s (%s)", oldName, newName, attributes.get(oldName)));
attributes.put(newName, attributes.get(oldName));
attributes.remove(oldName);
} else {
_logger.debug(String.format("attributeRemapping: attribute not found (%s)", oldName));
}
}
}
@@ -0,0 +1,17 @@
package org.maxkey.authn.support.wsfederation;
import java.util.Map;
/**
* This interface provides a mechanism to alter the SAML attributes before they
* are added the WsFederationCredentials and returned to Sec
*/
public interface WsFederationAttributeMutator {
/**
* modifyAttributes manipulates the attributes before they are assigned to the credential.
*
* @param attributes the attribute returned by the IdP.
*/
void modifyAttributes(Map<String, Object> attributes,String upnSuffix);
}
@@ -0,0 +1,159 @@
package org.maxkey.authn.support.wsfederation;
import org.opensaml.xml.security.x509.BasicX509Credential;
import org.springframework.core.io.Resource;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
/**
* This class gathers configuration information for the WS Federation Identity Provider.
*
*/
public final class WsFederationConfiguration {
@NotNull
private String identifier;
@NotNull
private String url;
@NotNull
private String principal;
@NotNull
private String relyingParty;
private String upnSuffix;
@NotNull
private List<Resource> signingCertificates;
private int tolerance = 10000;
private List<BasicX509Credential> signingWallet;
private WsFederationAttributeMutator attributeMutator;
private String logoutUrl;
public String getIdentifier() {
return identifier;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getPrincipal() {
return principal;
}
public void setPrincipal(String principal) {
this.principal = principal;
}
public String getRelyingParty() {
return relyingParty;
}
public void setRelyingParty(String relyingParty) {
this.relyingParty = relyingParty;
}
public List<BasicX509Credential> getSigningWallet() {
return signingWallet;
}
public void setSigningWallet(List<BasicX509Credential> signingWallet) {
this.signingWallet = signingWallet;
}
/**
* gets the signing certificates.
*
* @return X509credentials of the signing certs
*/
public List<BasicX509Credential> getSigningCertificates() {
return this.signingWallet;
}
/**
* sets the signing certs.
*
* @param signingCertificateFiles a list of certificate files to read in.
*/
public void setSigningCertificates(final List<Resource> signingCertificateFiles) {
this.signingCertificates = signingCertificateFiles;
final List<BasicX509Credential> signingCerts = new ArrayList<BasicX509Credential>();
for (Resource file : signingCertificateFiles) {
signingCerts.add(WsFederationUtils.getSigningCredential(file));
}
this.signingWallet = signingCerts;
}
/**
* gets the tolerance.
*
* @return the tolerance in milliseconds
*/
public int getTolerance() {
return tolerance;
}
/**
* sets the tolerance of the validity of the timestamp token.
*
* @param tolerance the tolerance in milliseconds
*/
public void setTolerance(final int tolerance) {
this.tolerance = tolerance;
}
/**
* gets the attributeMutator.
*
* @return an attributeMutator
*/
public WsFederationAttributeMutator getAttributeMutator() {
return attributeMutator;
}
/**
* sets the attributeMutator.
*
* @param attributeMutator an attributeMutator
*/
public void setAttributeMutator(final WsFederationAttributeMutator attributeMutator) {
this.attributeMutator = attributeMutator;
}
public String getUpnSuffix() {
return upnSuffix;
}
public void setUpnSuffix(String upnSuffix) {
this.upnSuffix = upnSuffix;
}
public String getLogoutUrl() {
return logoutUrl;
}
public void setLogoutUrl(String logoutUrl) {
this.logoutUrl = logoutUrl;
}
}
@@ -0,0 +1,14 @@
package org.maxkey.authn.support.wsfederation;
public class WsFederationConstants {
public static final String LOCALE = "locale";
public static final String METHOD = "method";
public static final String PROVIDERURL = "WsFederationIdentityProviderUrl";
public static final String QUERYSTRING = "?wa=wsignin1.0&wtrealm=";
public static final String SERVICE = "service";
public static final String THEME = "theme";
public static final String WA = "wa";
public static final String WCTX = "wctx";
public static final String WRESULT = "wresult";
public static final String WSIGNIN = "wsignin1.0";
}
@@ -0,0 +1,152 @@
package org.maxkey.authn.support.wsfederation;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
/**
* This class represents the basic elements of the WsFederation token.
*
*/
public final class WsFederationCredential {
private final Logger _logger = LoggerFactory.getLogger(WsFederationCredential.class);
private String audience;
private String authenticationMethod;
private String id;
private String issuer;
private DateTime issuedOn;
private DateTime notBefore;
private DateTime notOnOrAfter;
private DateTime retrievedOn;
private Map<String, Object> attributes;
public String getAuthenticationMethod() {
return this.authenticationMethod;
}
public void setAuthenticationMethod(final String authenticationMethod) {
this.authenticationMethod = authenticationMethod;
}
public String getAudience() {
return this.audience;
}
public void setAudience(final String audience) {
this.audience = audience;
}
public Map<String, Object> getAttributes() {
return this.attributes;
}
public void setAttributes(final Map<String, Object> attributes) {
this.attributes = attributes;
}
public String getId() {
return this.id;
}
public void setId(final String id) {
this.id = id;
}
public DateTime getIssuedOn() {
return this.issuedOn;
}
public void setIssuedOn(final DateTime issuedOn) {
this.issuedOn = issuedOn;
}
public String getIssuer() {
return this.issuer;
}
public void setIssuer(final String issuer) {
this.issuer = issuer;
}
public DateTime getNotBefore() {
return this.notBefore;
}
public void setNotBefore(final DateTime notBefore) {
this.notBefore = notBefore;
}
public DateTime getNotOnOrAfter() {
return this.notOnOrAfter;
}
public void setNotOnOrAfter(final DateTime notOnOrAfter) {
this.notOnOrAfter = notOnOrAfter;
}
public DateTime getRetrievedOn() {
return this.retrievedOn;
}
public void setRetrievedOn(final DateTime retrievedOn) {
this.retrievedOn = retrievedOn;
}
/**
* toString produces a human readable representation of the WsFederationCredential.
*
* @return a human readable representation of the WsFederationCredential
*/
@Override
public String toString() {
String attributeList = "";
for (String attr : this.attributes.keySet()) {
attributeList += " " + attr + ": " + (attributes.get(attr)).toString() + "\n";
}
final String readable = "ID: %s\nIssuer: %s\nAudience: %s\nAudience Method: %s\nIssued On: %s\n"
+ "Valid After: %s\nValid Before: %s\nAttributes:\n%s";
return String.format(readable, this.id, this.issuer, this.audience, this.authenticationMethod,
this.issuedOn.toString(), this.notBefore.toString(), this.notOnOrAfter.toString(), attributeList);
}
/**
* isValid validates the credential.
*
* @param expectedAudience the audience that the token was issued to (CAS Server)
* @param expectedIssuer the issuer of the token (the IdP)
* @param timeDrift the amount of acceptable time drift
* @return true if the credentials are valid, otherwise false
*/
public boolean isValid(final String expectedAudience, final String expectedIssuer, final int timeDrift) {
if (!this.getAudience().equalsIgnoreCase(expectedAudience)) {
_logger.warn(".isValid: audience is invalid: {}", this.getAudience());
return false;
}
if (!this.getIssuer().equalsIgnoreCase(expectedIssuer)) {
_logger.warn(".isValid: issuer is invalid: {}", this.getIssuer());
return false;
}
if (this.getIssuedOn().isBefore(this.getRetrievedOn().minusMillis(timeDrift))
|| this.getIssuedOn().isAfter(this.getRetrievedOn().plusMillis(timeDrift))) {
_logger.warn(".isValid: Ticket outside of drift.");
return false;
}
if (this.getRetrievedOn().isAfter(this.getNotOnOrAfter())) {
_logger.warn(".isValid: ticket is too late.");
return false;
}
_logger.debug(".isValid: credential is valid.");
return true;
}
}
@@ -0,0 +1,8 @@
package org.maxkey.authn.support.wsfederation;
import javax.servlet.http.HttpServletRequest;
public interface WsFederationService {
public boolean login(String wsFederationWA,String wsFederationWResult,HttpServletRequest request);
}
@@ -0,0 +1,65 @@
package org.maxkey.authn.support.wsfederation;
import javax.servlet.http.HttpServletRequest;
import org.maxkey.constants.LOGINTYPE;
import org.maxkey.util.StringUtils;
import org.maxkey.web.WebContext;
import org.opensaml.saml1.core.impl.AssertionImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class WsFederationServiceImpl implements WsFederationService{
final static Logger _logger = LoggerFactory.getLogger(WsFederationServiceImpl.class);
private WsFederationConfiguration wsFederationConfiguration;
public boolean login(String wsFederationWA,String wsFederationWResult,HttpServletRequest request){
// it's an authentication
if (StringUtils.isNotEmpty(wsFederationWA) && wsFederationWA.equalsIgnoreCase(WsFederationConstants.WSIGNIN)) {
_logger.debug("wresult : {}"+wsFederationWResult);
final String wctx = request.getParameter(WsFederationConstants.WCTX);
_logger.debug("wctx : {}"+ wctx);
// create credentials
final AssertionImpl assertion = WsFederationUtils.parseTokenFromString(wsFederationWResult);
//Validate the signature
if (assertion != null && WsFederationUtils.validateSignature(assertion, wsFederationConfiguration.getSigningCertificates())) {
final WsFederationCredential wsFederationCredential = WsFederationUtils.createCredentialFromToken(assertion);
if (wsFederationCredential != null && wsFederationCredential.isValid(wsFederationConfiguration.getRelyingParty(),
wsFederationConfiguration.getIdentifier(),
wsFederationConfiguration.getTolerance())) {
//Give the library user a chance to change the attributes as necessary
if (wsFederationConfiguration.getAttributeMutator() != null) {
wsFederationConfiguration.getAttributeMutator().modifyAttributes(
wsFederationCredential.getAttributes(),
wsFederationConfiguration.getUpnSuffix());
}
return WebContext.setAuthentication(
wsFederationCredential.getAttributes().get("").toString(),
LOGINTYPE.WSFEDERATION,
"","","success");
} else {
_logger.warn("SAML assertions are blank or no longer valid.");
return false;
}
} else {
_logger.error("WS Requested Security Token is blank or the signature is not valid.");
return false;
}
}
return false;
}
public void setWsFederationConfiguration(
WsFederationConfiguration wsFederationConfiguration) {
this.wsFederationConfiguration = wsFederationConfiguration;
}
}
@@ -0,0 +1,269 @@
package org.maxkey.authn.support.wsfederation;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.opensaml.DefaultBootstrap;
import org.opensaml.saml1.core.Attribute;
import org.opensaml.saml1.core.Conditions;
import org.opensaml.saml1.core.impl.AssertionImpl;
import org.opensaml.ws.wsfed.RequestedSecurityToken;
import org.opensaml.ws.wsfed.impl.RequestSecurityTokenResponseImpl;
import org.opensaml.xml.Configuration;
import org.opensaml.xml.ConfigurationException;
import org.opensaml.xml.io.Unmarshaller;
import org.opensaml.xml.io.UnmarshallerFactory;
import org.opensaml.xml.io.UnmarshallingException;
import org.opensaml.xml.parse.BasicParserPool;
import org.opensaml.xml.parse.XMLParserException;
import org.opensaml.xml.schema.XSAny;
import org.opensaml.xml.security.x509.BasicX509Credential;
import org.opensaml.xml.signature.Signature;
import org.opensaml.xml.signature.SignatureValidator;
import org.opensaml.xml.validation.ValidationException;
import org.springframework.core.io.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* Helper class that does the heavy lifting with the openSaml library.
*
*/
public final class WsFederationUtils {
/**
* Initialized the openSaml library.
*/
static {
final Logger _logger = LoggerFactory.getLogger(WsFederationUtils.class);
try {
// Initialize the library
DefaultBootstrap.bootstrap();
} catch (final ConfigurationException ex) {
_logger.error(ex.getMessage());
}
}
/**
* private constructor.
*/
private WsFederationUtils() {
}
/**
* createCredentialFromToken converts a SAML 1.1 assertion to a WSFederationCredential.
*
* @param assertion the provided assertion
* @return an equivalent credential.
*/
public static WsFederationCredential createCredentialFromToken(final AssertionImpl assertion) {
final Logger _logger = LoggerFactory.getLogger(WsFederationUtils.class);
final DateTime retrievedOn = new DateTime().withZone(DateTimeZone.UTC);
_logger.debug("createCredentialFromToken: retrieved on {}", retrievedOn.toString());
final WsFederationCredential credential = new WsFederationCredential();
credential.setRetrievedOn(retrievedOn);
credential.setId(assertion.getID());
credential.setIssuer(assertion.getIssuer());
credential.setIssuedOn(assertion.getIssueInstant());
final Conditions conditions = assertion.getConditions();
if (conditions != null) {
credential.setNotBefore(conditions.getNotBefore());
credential.setNotOnOrAfter(conditions.getNotOnOrAfter());
credential.setAudience(conditions.getAudienceRestrictionConditions().get(0).getAudiences().get(0).getUri());
}
if (assertion.getAuthenticationStatements() != null && assertion.getAuthenticationStatements().size() > 0) {
credential.setAuthenticationMethod(assertion.getAuthenticationStatements().get(0).getAuthenticationMethod());
}
//retrieve an attributes from the assertion
final HashMap<String, Object> attributes = new HashMap<String, Object>();
for (Attribute item : assertion.getAttributeStatements().get(0).getAttributes()) {
_logger.debug("createCredentialFromToken: processed attribute: {}", item.getAttributeName());
if (item.getAttributeValues().size() == 1) {
attributes.put(item.getAttributeName(), ((XSAny) item.getAttributeValues().get(0)).getTextContent());
} else {
final ArrayList<String> itemList = new ArrayList<String>();
for (int i = 0; i < item.getAttributeValues().size(); i++) {
itemList.add(((XSAny) item.getAttributeValues().get(i)).getTextContent());
}
if (!itemList.isEmpty()) {
attributes.put(item.getAttributeName(), itemList);
}
}
}
credential.setAttributes(attributes);
_logger.debug("createCredentialFromToken: {}", credential.toString());
return credential;
}
/**
* getSigningCredential loads up an X509Credential from a file.
*
* @param resource the signing certificate file
* @return an X509 credential
*/
public static BasicX509Credential getSigningCredential(final Resource resource) {
final Logger _logger = LoggerFactory.getLogger(WsFederationUtils.class);
BasicX509Credential publicCredential;
try {
//grab the certificate file
final InputStream inputStream = resource.getInputStream();
final CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
final X509Certificate certificate = (X509Certificate) certificateFactory.generateCertificate(inputStream);
try {
inputStream.close();
} catch (final IOException ex) {
_logger.warn("Error closing the signing cert file: {}", ex.getMessage());
}
//get the public key from the certificate
final X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(certificate.getPublicKey().getEncoded());
//generate public key to validate signatures
final KeyFactory keyFactory = KeyFactory.getInstance("RSA");
final PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
//add the public key
publicCredential = new BasicX509Credential();
publicCredential.setPublicKey(publicKey);
} catch (final CertificateException ex) {
_logger.error("Error retrieving the signing cert: {}", ex.getMessage());
return null;
} catch (final InvalidKeySpecException ex) {
_logger.error("Error retrieving the signing cert: {}", ex.getMessage());
return null;
} catch (final NoSuchAlgorithmException ex) {
_logger.error("Error retrieving the signing cert: {}", ex.getMessage());
return null;
} catch (final IOException ex) {
_logger.error("Error retrieving the signing cert: " + ex.getMessage());
return null;
}
_logger.debug("getSigningCredential: key retrieved.");
return publicCredential;
}
/**
* parseTokenFromString converts a raw wresult and extracts it into an assertion.
*
* @param wresult the raw token returned by the IdP
* @return an assertion
*/
public static AssertionImpl parseTokenFromString(final String wresult) {
final Logger _logger = LoggerFactory.getLogger(WsFederationUtils.class);
RequestSecurityTokenResponseImpl rsToken;
final BasicParserPool parserPool = new BasicParserPool();
parserPool.setNamespaceAware(true);
try {
final InputStream in = new ByteArrayInputStream(wresult.getBytes("UTF-8"));
final Document document = parserPool.parse(in);
final Element metadataRoot = document.getDocumentElement();
final UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory();
final Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(metadataRoot);
rsToken = (RequestSecurityTokenResponseImpl) unmarshaller.unmarshall(metadataRoot);
} catch (final UnmarshallingException ex) {
_logger.warn(ex.getMessage());
return null;
} catch (final XMLParserException ex) {
_logger.warn(ex.getMessage());
return null;
} catch (final UnsupportedEncodingException ex) {
_logger.warn(ex.getMessage());
return null;
}
//Get our SAML token
final List<RequestedSecurityToken> rst = rsToken.getRequestedSecurityToken();
final AssertionImpl assertion = (AssertionImpl) rst.get(0).getSecurityTokens().get(0);
if (assertion == null) {
_logger.debug("parseTokenFromString: assertion null");
} else {
_logger.debug("parseTokenFromString: {}", assertion.toString());
}
return assertion;
}
/**
* validateSignature checks to see if the signature on an assertion is valid.
*
* @param assertion a provided assertion
* @param x509Creds list of x509certs to check.
* @return true if the assertion's signature is valid, otherwise false
*/
public static boolean validateSignature(final AssertionImpl assertion, final List<BasicX509Credential> x509Creds) {
final Logger _logger = LoggerFactory.getLogger(WsFederationUtils.class);
SignatureValidator signatureValidator;
for (BasicX509Credential cred : x509Creds) {
try {
signatureValidator = new SignatureValidator(cred);
} catch (final Exception ex) {
_logger.warn(ex.getMessage());
break;
}
//get the signature to validate from the response object
final Signature signature = assertion.getSignature();
//try to validate
try {
signatureValidator.validate(signature);
_logger.debug("validateSignature: Signature is valid.");
return true;
} catch (final ValidationException ex) {
_logger.warn("validateSignature: Signature is NOT valid.");
_logger.warn(ex.getMessage());
}
}
_logger.warn("validateSignature: Signature doesn't match any signing credential.");
return false;
}
}
@@ -0,0 +1,8 @@
/**
*
*/
/**
* @author Administrator
*
*/
package org.maxkey;