/* * Copyright [2020] [MaxKey of copyright http://www.maxkey.top] * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.maxkey.web.endpoint; import java.util.Iterator; import java.util.Set; import java.util.UUID; 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; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.savedrequest.SavedRequest; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @Api(tags = "1-3-单点注销接口文档模块") @Controller public class LogoutEndpoint { private static Logger _logger = LoggerFactory.getLogger(LogoutEndpoint.class); public static final String RE_LOGIN_URL = "reLoginUrl"; @Autowired @Qualifier("authenticationRealm") AbstractAuthenticationRealm authenticationRealm; @Autowired ApplicationConfig applicationConfig; @Autowired @Qualifier("onlineTicketServices") protected OnlineTicketServices onlineTicketServices; @ApiOperation(value = "单点注销接口", notes = "reLoginUrl跳转地址",httpMethod="GET") @RequestMapping(value={"/logout"}) public ModelAndView logout( HttpServletRequest request, HttpServletResponse response, @RequestParam(value=RE_LOGIN_URL,required=false) String reLoginUrl){ return logoutModelAndView(request,response,"loggedout",reLoginUrl); } @ApiOperation(value = "登录超时接口", notes = "",httpMethod="GET") @RequestMapping(value={"/timeout"}) public ModelAndView timeout(HttpServletRequest request, HttpServletResponse response){ return logoutModelAndView(request,response,"timeout",null); } private ModelAndView logoutModelAndView( HttpServletRequest request, HttpServletResponse response, String viewName, String reLoginUrl){ ModelAndView modelAndView = new ModelAndView(); authenticationRealm.logout(response); if(reLoginUrl==null){ SavedRequest firstSavedRequest = (SavedRequest)WebContext.getAttribute(WebConstants.FIRST_SAVED_REQUEST_PARAMETER); reLoginUrl=WebContext.getHttpContextPath()+"/login"; if(firstSavedRequest!=null){ reLoginUrl= firstSavedRequest.getRedirectUrl(); WebContext.removeAttribute(WebConstants.FIRST_SAVED_REQUEST_PARAMETER); } } //not start with http or https if(reLoginUrl!=null && !reLoginUrl.toLowerCase().startsWith("http")) { reLoginUrl=WebContext.getHttpContextPath()+"/"+reLoginUrl; } _logger.debug("re Login URL : "+ reLoginUrl); modelAndView.addObject("reloginUrl",reLoginUrl); String onlineTicketId = ((SigninPrincipal)WebContext.getAuthentication().getPrincipal()).getOnlineTicket().getTicketId(); OnlineTicket onlineTicket = onlineTicketServices.get(onlineTicketId); Set<Entry<String, Apps>> entrySet = onlineTicket.getAuthorizedApps().entrySet(); Iterator<Entry<String, Apps>> iterator = entrySet.iterator(); while (iterator.hasNext()) { Entry<String, Apps> 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); //remove ONLINE_TICKET cookie WebContext.expiryCookie(WebContext.getResponse(), this.applicationConfig.getBaseDomainName(), WebConstants.ONLINE_TICKET_NAME, UUID.randomUUID().toString()); request.getSession().invalidate(); SecurityContextHolder.clearContext(); modelAndView.setViewName(viewName); return modelAndView; } }