@Override protected void allowableSessionsExceeded(List<SessionInformation> sessions, int allowableSessions, SessionRegistry registry) throws SessionAuthenticationException { SessionInformation leastRecentlyUsed = null; for (SessionInformation session : sessions) { if ((leastRecentlyUsed == null) || session.getLastRequest().before(leastRecentlyUsed.getLastRequest())) { leastRecentlyUsed = session; } } if(leastRecentlyUsed instanceof SessionInformationObject){ SessionInformationObject sessionObject=(SessionInformationObject)leastRecentlyUsed; sessionObject.setKickAway(true); } leastRecentlyUsed.expireNow(); }
@Test(expected = SessionAuthenticationException.class) public void testUnsuccessfulAuthWithIncorrectUser() throws IOException { formLoginAuthenticationCsrfTokenInterceptor.setCredentialProvider(new CredentialProvider() { @Override public String getUsername() { return "badUser"; } @Override public String getPassword() { return credentialProvider.getPassword(); } }); String result = authenticatedRestTemplate.getForObject("", String.class); }
@Test(expected = SessionAuthenticationException.class) public void testUnsuccessfulAuthWithIncorrectPassword() throws IOException { formLoginAuthenticationCsrfTokenInterceptor.setCredentialProvider(new CredentialProvider() { @Override public String getUsername() { return credentialProvider.getUsername(); } @Override public String getPassword() { return "bad password"; } }); String result = authenticatedRestTemplate.getForObject("", String.class); }
public void doFilter(ServletRequest baseRequest, ServletResponse baseResponse, FilterChain chain) throws IOException, ServletException { try { super.doFilter(baseRequest, baseResponse, chain); } catch (ServletException e) { if (e.getCause() instanceof ServiceException) { HttpServletRequest baseHttpRequest = (HttpServletRequest) baseRequest; //if authentication is null and CSRF token is invalid, must be session time out if (SecurityContextHolder.getContext().getAuthentication() == null) { baseHttpRequest.setAttribute("sessionTimeout", true); failureHandler.onAuthenticationFailure((HttpServletRequest) baseRequest, (HttpServletResponse) baseResponse, new SessionAuthenticationException("Session Time Out")); } else { throw e; } } else { throw e; } } }
/** * Send the given message to all users after checking the authorization of the user. * @param message The message to be sent. * @param accessToken The oauth2 accessToken of the user. * @return the message to the topic * @throws Exception Thrown if not authorized for instance. */ @MessageMapping("/user-messages") @SendTo("/topic/user-messages") public MessageDto sendMessageToAllUsers(MessageDto message, @Header("access_token") String accessToken) throws Exception { OAuth2AccessToken oauth2accessToken = tokenStore.readAccessToken(accessToken); if (oauth2accessToken != null) { OAuth2Authentication authentication = tokenStore.readAuthentication(oauth2accessToken); if (authentication != null && authentication.getAuthorities().contains( new SimpleGrantedAuthority("ROLE_ADMIN"))) { message.setSender(authentication.getUserAuthentication().getName()); log.debug("Sending message from {} to all users", message.getSender()); return message; } } log.error("Unauthorized message from {} with content: {}", message.getSender(), message.getText()); throw new SessionAuthenticationException("No valid access token found!"); }
@Override protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { final FirebaseAuthenticationToken authenticationToken = (FirebaseAuthenticationToken) authentication; final CompletableFuture<FirebaseToken> future = new CompletableFuture<>(); firebaseAuth.verifyIdToken(authenticationToken.getToken()).addOnSuccessListener(future::complete); try { final FirebaseToken token = future.get(); return new FirebaseUserDetails(token.getEmail(), token.getUid()); } catch (InterruptedException | ExecutionException e) { throw new SessionAuthenticationException(e.getMessage()); } }
@ExceptionHandler({ SessionLimitExceededException.class, HttpSessionRequiredException.class, SessionException.class, SessionAuthenticationException.class, }) public String handleSessionRequired(Exception e, RedirectAttributes attr){ attr.addFlashAttribute("error","Your session has been expired. Please log in again."); return "redirect:/error"; }
@ExceptionHandler({ HttpSessionRequiredException.class, SessionException.class, SessionAuthenticationException.class, }) public String handleSessionRequired(Exception e, RedirectAttributes attr){ e.printStackTrace(); attr.addFlashAttribute("error","Your session has been expired. Please log in again."); return "redirect:/oups"; }
/** * @param request the request, containing method, URI, and headers * @param csrfToken the CSRF token to be injected into the request header */ protected void injectCsrfTokenIntoHeader(HttpRequest request, CsrfToken csrfToken) { if (csrfToken == null) { throw new SessionAuthenticationException("There is no CSRF token to inject"); } logger.debug("Injecting CSRF token into request {} header: {}", request.getURI(), csrfToken.getToken()); request.getHeaders().add(csrfToken.getHeaderName(), csrfToken.getToken()); }
/** * Starts the traditioanl form login authentication flow handshake. * Consequencially, the cookie store (which contains the session id) and the * CSRF token will be updated. * * @throws AuthenticationException */ protected synchronized void startAuthenticationFlow() throws AuthenticationException { logger.debug("Getting authenticated session"); logger.debug("Start by loading up the login form to get a valid unauthenticated session and CSRF token"); ResponseEntity<String> loginResponseEntity = restTemplateForAuthenticationFlow.getForEntity(authRestTemplate.getURIForResource(formLoginConfig.getLoginFormPath()), String.class); latestCsrfToken = getCsrfTokenFromLoginHtml(loginResponseEntity.getBody()); latestSessionIdForLatestCsrfToken = getAuthenticationSessionIdFromCookieStore(); logger.debug("Update CSRF token for interceptor ({}) from login form", latestCsrfToken.getToken()); MultiValueMap<String, Object> loginPostParams = new LinkedMultiValueMap<>(); loginPostParams.add("username", credentialProvider.getUsername()); loginPostParams.add("password", credentialProvider.getPassword()); logger.debug("Post to login url to startAuthenticationFlow with user={}, pwd={}", credentialProvider.getUsername(), credentialProvider.getPassword()); ResponseEntity<String> postLoginResponseEntity = restTemplateForAuthenticationFlow.postForEntity(authRestTemplate.getURIForResource(formLoginConfig.getLoginFormPath()), loginPostParams, String.class); //TODO(P1) This current way of checking if authentication is successful is somewhat // hacky. Bascailly it says that authentication is successful if a 302 is returned // and the redirect (from location header) maps to the login redirect path from the config. URI locationURI = URI.create(postLoginResponseEntity.getHeaders().get("Location").get(0)); String expectedLocation = resttemplateConfig.getContextPath() + "/" + formLoginConfig.getLoginRedirectPath(); if (postLoginResponseEntity.getStatusCode().equals(HttpStatus.FOUND) && expectedLocation.equals(locationURI.getPath())) { latestCsrfToken = getCsrfTokenFromEndpoint(authRestTemplate.getURIForResource(formLoginConfig.getCsrfTokenPath())); latestSessionIdForLatestCsrfToken = getAuthenticationSessionIdFromCookieStore(); logger.debug("Update CSRF token interceptor in AuthRestTempplate ({})", latestCsrfToken.getToken()); } else { throw new SessionAuthenticationException("Authentication failed. Post login status code = " + postLoginResponseEntity.getStatusCode() + ", location = [" + locationURI.getPath() + "], expected location = [" + expectedLocation + "]"); } }
/** * Gets the CSRF token from login html because the CSRF token endpoint needs * to be authenticated first. * * @param loginHtml The login page HTML which contains the csrf token. It is * assumed that the CSRF token is embedded on the page inside an input field * with name matching * {@link com.box.l10n.mojito.rest.resttemplate.FormLoginAuthenticationCsrfTokenInterceptor#CSRF_PARAM_NAME} * @return * @throws AuthenticationException */ protected CsrfToken getCsrfTokenFromLoginHtml(String loginHtml) throws AuthenticationException { Pattern pattern = Pattern.compile("CSRF_TOKEN = '(.*?)';"); Matcher matcher = pattern.matcher(loginHtml); if (matcher.find()) { String csrfTokenString = matcher.group(1); logger.debug("CSRF token from login html: {}", csrfTokenString); return new DefaultCsrfToken(CSRF_HEADER_NAME, CSRF_PARAM_NAME, csrfTokenString); } else { throw new SessionAuthenticationException("Could not find CSRF_TOKEN variable on login page"); } }
/** * This method has been copied from ConcurrentSessionControlStrategy and modified to * better ensure that more that the allowed number of sessions are never valid * at the same time. * * @see ConcurentSessionControlStrategy.allowableSessionsExceeded */ protected void allowableSessionsExceeded(List<SessionInformation> sessions, int allowableSessions, SessionRegistry registry) throws SessionAuthenticationException { if (exceptionIfMaximumExceeded || (sessions == null)) { throw new SessionAuthenticationException(messages.getMessage( "ConcurrentSessionControlStrategy.exceededAllowed", new Object[] {new Integer(allowableSessions)}, "Maximum sessions of {0} for this principal exceeded")); } //BEGIN CUSTOMIZATIONS log.debug("allowableSessionExceeded. allowed: " + allowableSessions + " Current: " + sessions.size()); //sort the session by recency, increasing Collections.sort(sessions, comparator); //note - sessions does not include the new session being authenticated int sessionsToExpire = sessions.size() - allowableSessions + 1; //remove the first sessionToExpire sessions from the sorted list for (int i = 0; i < sessionsToExpire; i++) { sessions.get(i).expireNow(); } }
@Override public void onAuthentication(Authentication authentication, HttpServletRequest request, HttpServletResponse response) throws SessionAuthenticationException { // Set the authentication in the current context SecurityContextHolder.getContext().setAuthentication(authentication); }
@GetMapping(params = "error") public String getLoginErrorPage(Model model, HttpServletRequest request) { String errorMessage; Object attribute = request.getSession().getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION); if (attribute != null) { if (attribute instanceof BadCredentialsException) { errorMessage = ERROR_MESSAGE_BAD_CREDENTIALS; } else if (attribute instanceof SessionAuthenticationException) { errorMessage = ERROR_MESSAGE_SESSION_AUTHENTICATION; } else { if (!determineErrorMessagesFromInternalAuthenticationExceptions(attribute).isEmpty()) { errorMessage = determineErrorMessagesFromInternalAuthenticationExceptions(attribute); } else { errorMessage = ERROR_MESSAGE_UNKNOWN; } } } else { errorMessage = ERROR_MESSAGE_UNKNOWN; } model.addAttribute(ERROR_MESSAGE_ATTRIBUTE, errorMessage); return VIEW_LOGIN; }
/** * 自定义UserDetailsService,从数据库中读取用户信息 * @return */ @Bean public UserDetailsService customUserDetailsService(){ return new UserDetailsService(){ @Autowired private UserService userService; @Autowired private SessionRegistry sessionRegistry; @Override public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException { //User对应数据库中的用户表,是最终存储用户和密码的表,可自定义 org.gra4j.dataMigration.crud.entity.User user = userService.findUserByName(userName); if (user == null) { throw new UsernameNotFoundException("UserName " + userName + " not found"); } //用户已经登录则此次登录失败 List<Object> o = sessionRegistry.getAllPrincipals(); for ( Object principal : o) { if (principal instanceof org.gra4j.dataMigration.crud.entity.User && (user.getUserName().equals(((org.gra4j.dataMigration.crud.entity.User) principal).getUserName()))) { throw new SessionAuthenticationException("当前用户已经在线,登录失败!!!"); } } //List<Permission> permissions = permissionDao.findByAdminUserId(user.getId()); List<GrantedAuthority> grantedAuthorities = new ArrayList<>(); /*for (Permission permission : permissions) { if (permission != null && permission.getName()!=null) { GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permission.getName()); //1:此处将权限信息添加到 GrantedAuthority 对象中,在后面进行全权限验证时会使用GrantedAuthority 对象。 grantedAuthorities.add(grantedAuthority); } }*/ return new User(user.getUserName(), user.getPassword(), grantedAuthorities); } }; }
public void run(String... args) { Exception parsingException = null; try { logger.debug("Parse arguments"); jCommander.parse(args); } catch (Exception e) { parsingException = e; logger.debug("Parsing failed", e); } String parsedCommand = jCommander.getParsedCommand(); if (parsingException != null) { logger.debug("Parsing failed, show help"); printErrorMessage(parsingException.getMessage()); if (parsedCommand == null) { usage(); } else { usage(parsedCommand); } } else { logger.debug("Execute commands for parsed command: {}", parsedCommand); Command command = getCommand(parsedCommand); try { command.run(); } catch (SessionAuthenticationException ae) { logger.debug("Exit with Invalid username or password", ae); printErrorMessage("Invalid username or password"); exitWithError(); } catch (CommandException ce) { printErrorMessage(ce.getMessage()); logger.error("Exit with error for command: " + command.getName(), ce); exitWithError(); } catch (ResourceAccessException rae) { String msg = "Is a server running on: " + authenticatedRestTemplate.getURIForResource("") + "?"; printErrorMessage(msg); logger.error(msg, rae); exitWithError(); } catch (Throwable t) { printErrorMessage("Unexpected error, see logs for more information"); logger.error("Unexpected error", t); exitWithError(); } } }
/** * Allowable sessions exceeded. * * @param sessions * the sessions * @param allowableSessions * the allowable sessions * @param sameIp * the same ip * @param registry * the registry * @throws SessionAuthenticationException * the session authentication exception */ protected void allowableSessionsExceeded(java.util.List<SessionInformation> sessions, int allowableSessions, boolean sameIp, SessionRegistry registry) throws SessionAuthenticationException { // new IP handle if (!sameIp) { // deny login if exceptionIfMaximumExceeded if (exceptionIfMaximumExceeded || (sessions == null)) { throw new SessionAuthenticationException(messages.getMessage( "ConcurrentSessionControllerImpl.exceededAllowed", new Object[] { Integer.valueOf(allowableSessions) }, "Maximum sessions of {0} for this principal exceeded")); } } // Determine least recently used session, and mark it for invalidation SessionInformation leastRecentlyUsed = null; for (int i = 0; i < sessions.size(); i++) { if ((leastRecentlyUsed == null) || sessions.get(i).getLastRequest().before(leastRecentlyUsed.getLastRequest())) { leastRecentlyUsed = sessions.get(i); } } if (sessions.size() > allowableSessions && !sameIp) { BasicPrincipal basicPrincipal = (BasicPrincipal) leastRecentlyUsed.getPrincipal(); for (int i = 0; i < sessions.size(); i++) { if (sessions.get(i).getPrincipal().equals(leastRecentlyUsed.getPrincipal())) { if (basicPrincipal.equalsIp((BasicPrincipal) (sessions.get(i).getPrincipal()))) { sessions.get(i).expireNow(); } } } leastRecentlyUsed.expireNow(); } else if (!sameIp) { leastRecentlyUsed.expireNow(); } else { // TODO } }
@Override public Authentication updateAuthentication(Authentication authentication, List<GrantedAuthority> updatedAuthorities) { Authentication newAuthentication; if (authentication instanceof TwoFactorAuthenticationToken) { TwoFactorAuthenticationToken twoFactorAuthenticationToken = (TwoFactorAuthenticationToken) authentication; newAuthentication = new TwoFactorAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(), updatedAuthorities, twoFactorAuthenticationToken.getVerificationCode(), twoFactorAuthenticationToken.getSecretKey()); } else if (authentication instanceof SystemSecurityToken) { newAuthentication = authentication; } else if (authentication instanceof RestAuthenticationToken) { RestAuthenticationToken restAuthenticationToken = (RestAuthenticationToken) authentication; newAuthentication = new RestAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(), updatedAuthorities, restAuthenticationToken.getToken()); } else if (authentication instanceof RecoveryAuthenticationToken) { RecoveryAuthenticationToken recoveryAuthenticationToken = (RecoveryAuthenticationToken) authentication; newAuthentication = new RecoveryAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(), updatedAuthorities, recoveryAuthenticationToken.getRecoveryCode()); } else if (authentication instanceof UsernamePasswordAuthenticationToken) { newAuthentication = new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(), updatedAuthorities); } else if (authentication instanceof RunAsUserToken) { RunAsUserToken runAsUserToken = (RunAsUserToken) authentication; newAuthentication = new RunAsUserTokenDecorator(runAsUserToken, updatedAuthorities); } else if (authentication instanceof AnonymousAuthenticationToken) { AnonymousAuthenticationToken anonymousAuthenticationToken = (AnonymousAuthenticationToken) authentication; newAuthentication = new AnonymousAuthenticationTokenDecorator(anonymousAuthenticationToken, updatedAuthorities); } else { throw new SessionAuthenticationException( format("Unknown authentication type '%s'", authentication.getClass().getSimpleName())); } return newAuthentication; }
@Test(expectedExceptions = SessionAuthenticationException.class, expectedExceptionsMessageRegExp = "Unknown authentication type '.*?'") public void testUpdateAuthenticationUnknownToken() { authenticationAuthoritiesUpdaterImpl.updateAuthentication(mock(Authentication.class), updatedAuthorities); }