diff --git a/maxkey-protocols/maxkey-protocol-authorize/src/main/java/org/maxkey/authz/singlelogout/CasSingleLogout.java b/maxkey-protocols/maxkey-protocol-authorize/src/main/java/org/maxkey/authz/singlelogout/CasSingleLogout.java deleted file mode 100644 index 1451fae18..000000000 --- a/maxkey-protocols/maxkey-protocol-authorize/src/main/java/org/maxkey/authz/singlelogout/CasSingleLogout.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.maxkey.authz.singlelogout; - -public class CasSingleLogout extends SingleLogout{ - - public String logoutRequestMessage= - "%s" - + "%s"; - - @Override - public void sendRequest() { - // TODO Auto-generated method stub - - } - -} diff --git a/maxkey-protocols/maxkey-protocol-authorize/src/main/java/org/maxkey/authz/singlelogout/DefaultSingleLogout.java b/maxkey-protocols/maxkey-protocol-authorize/src/main/java/org/maxkey/authz/singlelogout/DefaultSingleLogout.java index 7ef581944..66101c81b 100644 --- a/maxkey-protocols/maxkey-protocol-authorize/src/main/java/org/maxkey/authz/singlelogout/DefaultSingleLogout.java +++ b/maxkey-protocols/maxkey-protocol-authorize/src/main/java/org/maxkey/authz/singlelogout/DefaultSingleLogout.java @@ -1,15 +1,24 @@ package org.maxkey.authz.singlelogout; +import java.util.HashMap; +import java.util.UUID; + +import org.maxkey.authn.SigninPrincipal; +import org.maxkey.domain.apps.Apps; +import org.maxkey.util.DateUtils; +import org.springframework.security.core.Authentication; + public class DefaultSingleLogout extends SingleLogout{ - public String logoutRequestMessage= - "%s" - + "%s"; - @Override - public void sendRequest() { - // TODO Auto-generated method stub + public void sendRequest(Authentication authentication,Apps logoutApp) { + HashMap logoutParameters = new HashMap(); + logoutParameters.put("id", UUID.randomUUID().toString()); + logoutParameters.put("principal", authentication.getName()); + logoutParameters.put("request", "logoutRequest"); + logoutParameters.put("issueInstant", DateUtils.getCurrentDateAsString(DateUtils.FORMAT_DATE_ISO_TIMESTAMP)); + logoutParameters.put("ticket", ((SigninPrincipal)authentication.getPrincipal()).getOnlineTicket().getTicketId()); + postMessage(logoutApp.getLogoutUrl(),logoutParameters); } diff --git a/maxkey-protocols/maxkey-protocol-authorize/src/main/java/org/maxkey/authz/singlelogout/SamlSingleLogout.java b/maxkey-protocols/maxkey-protocol-authorize/src/main/java/org/maxkey/authz/singlelogout/SamlSingleLogout.java new file mode 100644 index 000000000..3ef02284b --- /dev/null +++ b/maxkey-protocols/maxkey-protocol-authorize/src/main/java/org/maxkey/authz/singlelogout/SamlSingleLogout.java @@ -0,0 +1,40 @@ +package org.maxkey.authz.singlelogout; + +import java.util.HashMap; +import java.util.UUID; + +import org.maxkey.domain.apps.Apps; +import org.maxkey.util.DateUtils; +import org.springframework.security.core.Authentication; + +public class SamlSingleLogout extends SingleLogout{ + + /** + * The parameter name that contains the logout request. + */ + public static final String LOGOUT_REQUEST_PARAMETER = "logoutRequest"; + + public static final String logoutRequestMessage= + "%s" + + "%s"; + + @Override + public void sendRequest(Authentication authentication,Apps logoutApp) { + String requestMessage = String.format(logoutRequestMessage, + UUID.randomUUID().toString(), + DateUtils.getCurrentDateAsString(DateUtils.FORMAT_DATE_ISO_TIMESTAMP), + authentication.getName(), + logoutApp.getOnlineTicket() + ); + + HashMap logoutParameters = new HashMap(); + logoutParameters.put(LOGOUT_REQUEST_PARAMETER, requestMessage); + postMessage(logoutApp.getLogoutUrl(),logoutParameters); + } + + public SamlSingleLogout() { + super(); + } + +} diff --git a/maxkey-protocols/maxkey-protocol-authorize/src/main/java/org/maxkey/authz/singlelogout/SingleLogout.java b/maxkey-protocols/maxkey-protocol-authorize/src/main/java/org/maxkey/authz/singlelogout/SingleLogout.java index ccb9e6be4..6557dafdf 100644 --- a/maxkey-protocols/maxkey-protocol-authorize/src/main/java/org/maxkey/authz/singlelogout/SingleLogout.java +++ b/maxkey-protocols/maxkey-protocol-authorize/src/main/java/org/maxkey/authz/singlelogout/SingleLogout.java @@ -1,7 +1,101 @@ package org.maxkey.authz.singlelogout; -public abstract class SingleLogout { +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import org.apache.http.HttpEntity; +import org.apache.http.NameValuePair; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; +import org.maxkey.domain.apps.Apps; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.core.Authentication; + +public abstract class SingleLogout { + private static final Logger _logger = LoggerFactory.getLogger(SingleLogout.class); - public abstract void sendRequest() ; + public abstract void sendRequest(Authentication authentication,Apps logoutApp) ; + + public void postMessage(String url,Map paramMap) { + // 创建httpClient实例 + CloseableHttpClient httpClient = HttpClients.createDefault(); + CloseableHttpResponse httpResponse = null; + // 创建httpPost远程连接实例 + HttpPost httpPost = new HttpPost(url); + // 配置请求参数实例 + RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(35000)// 设置连接主机服务超时时间 + .setConnectionRequestTimeout(35000)// 设置连接请求超时时间 + .setSocketTimeout(60000)// 设置读取数据连接超时时间 + .build(); + // 为httpPost实例设置配置 + httpPost.setConfig(requestConfig); + // 设置请求头 + httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded"); + // 封装post请求参数 + if (null != paramMap && paramMap.size() > 0) { + List nvps = new ArrayList(); + // 通过map集成entrySet方法获取entity + Set> entrySet = paramMap.entrySet(); + // 循环遍历,获取迭代器 + Iterator> iterator = entrySet.iterator(); + while (iterator.hasNext()) { + Entry mapEntry = iterator.next(); + _logger.debug("Name " + mapEntry.getKey() + " , Value " +mapEntry.getValue()); + nvps.add(new BasicNameValuePair(mapEntry.getKey(), mapEntry.getValue().toString())); + } + + // 为httpPost设置封装好的请求参数 + try { + httpPost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8")); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } + + + try { + _logger.debug("Post URL " + url + " , Post Message \n" + + httpPost.getEntity().toString() + ); + // httpClient对象执行post请求,并返回响应参数对象 + httpResponse = httpClient.execute(httpPost); + // 从响应对象中获取响应内容 + HttpEntity entity = httpResponse.getEntity(); + _logger.debug("Http Response StatusCode " + + httpResponse.getStatusLine().getStatusCode()+ + " , Content " +EntityUtils.toString(entity) + ); + } catch (Exception e) { + e.printStackTrace(); + } finally { + // 关闭资源 + if (null != httpResponse) { + try { + httpResponse.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (null != httpClient) { + try { + httpClient.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } } diff --git a/maxkey-web-maxkey/src/main/java/org/maxkey/web/endpoint/LogoutEndpoint.java b/maxkey-web-maxkey/src/main/java/org/maxkey/web/endpoint/LogoutEndpoint.java index 1491b838c..2b1b867b5 100644 --- a/maxkey-web-maxkey/src/main/java/org/maxkey/web/endpoint/LogoutEndpoint.java +++ b/maxkey-web-maxkey/src/main/java/org/maxkey/web/endpoint/LogoutEndpoint.java @@ -17,13 +17,23 @@ package org.maxkey.web.endpoint; +import java.util.Iterator; +import java.util.Set; +import java.util.Map.Entry; + import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; - import org.maxkey.authn.SigninPrincipal; +import org.maxkey.authn.online.OnlineTicket; import org.maxkey.authn.online.OnlineTicketServices; import org.maxkey.authn.realm.AbstractAuthenticationRealm; +import org.maxkey.authz.singlelogout.SamlSingleLogout; +import org.maxkey.authz.singlelogout.DefaultSingleLogout; +import org.maxkey.authz.singlelogout.LogoutType; +import org.maxkey.authz.singlelogout.SingleLogout; import org.maxkey.configuration.ApplicationConfig; +import org.maxkey.constants.ConstantsProtocols; +import org.maxkey.domain.apps.Apps; import org.maxkey.web.WebConstants; import org.maxkey.web.WebContext; import org.slf4j.Logger; @@ -95,7 +105,26 @@ public class LogoutEndpoint { _logger.debug("re Login URL : "+ reLoginUrl); modelAndView.addObject("reloginUrl",reLoginUrl); - onlineTicketServices.remove(((SigninPrincipal)WebContext.getAuthentication().getPrincipal()).getOnlineTicket().getTicketId()); + String onlineTicketId = ((SigninPrincipal)WebContext.getAuthentication().getPrincipal()).getOnlineTicket().getTicketId(); + OnlineTicket onlineTicket = onlineTicketServices.get(onlineTicketId); + + Set> entrySet = onlineTicket.getAuthorizedApps().entrySet(); + + Iterator> iterator = entrySet.iterator(); + while (iterator.hasNext()) { + Entry mapEntry = iterator.next(); + _logger.debug("App Id : "+ mapEntry.getKey()+ " , " +mapEntry.getValue()); + if( mapEntry.getValue().getLogoutType() == LogoutType.BACK_CHANNEL){ + SingleLogout singleLogout; + if(mapEntry.getValue().getProtocol().equalsIgnoreCase(ConstantsProtocols.CAS)) { + singleLogout =new SamlSingleLogout(); + }else { + singleLogout = new DefaultSingleLogout(); + } + singleLogout.sendRequest(onlineTicket.getAuthentication(), mapEntry.getValue()); + } + } + onlineTicketServices.remove(onlineTicketId); request.getSession().invalidate(); SecurityContextHolder.clearContext();