package io.spotnext.spring.web.security;

import java.io.IOException;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.security.web.csrf.CsrfTokenRepository;

import io.spotnext.core.infrastructure.exception.SerializationException;
import io.spotnext.core.infrastructure.http.DataResponse;
import io.spotnext.core.infrastructure.service.SerializationService;
import io.spotnext.spring.web.dto.UserStatus;

/**
 * This handler implementation combines a few spring security handlers together.
 * It is primarily useful for RESTful services.
 *
 * @author mojo2012
 * @version 1.0
 * @since 1.0
 */
public class RestAuthenticationHandler implements AuthenticationEntryPoint, AuthenticationSuccessHandler,
		AuthenticationFailureHandler, LogoutSuccessHandler, AccessDeniedHandler {

	@Resource
	protected CsrfTokenRepository csrfTokenRepository;

	@Resource
	protected SerializationService serializationService;

	/**
	 * {@inheritDoc}
	 *
	 * Aborts a request in case it is not authenticated. It don't sends the
	 * www-authenticate header though as this would show a login box in the
	 * browser..
	 */
	@Override
	public void commence(final HttpServletRequest request, final HttpServletResponse response,
			final AuthenticationException exception) throws IOException, ServletException {

		onAuthenticationFailure(request, response, exception);
	}

	////////////////////////////////////////////////////////////////////////////////////////
	// authentication responses
	////////////////////////////////////////////////////////////////////////////////////////

	/**
	 * {@inheritDoc}
	 *
	 * Called when authentication was success.
	 */
	@Override
	public void onAuthenticationSuccess(final HttpServletRequest request, final HttpServletResponse response,
			final Authentication authentication) throws IOException, ServletException {

		final UserStatus ret = new UserStatus();
		ret.setAuthenticated(true);
		ret.setSessionId(request.getSession().getId());
		ret.setUsername(getUsername(authentication));

		final CsrfToken token = (CsrfToken) request.getAttribute(CsrfToken.class.getName());

		sendResponse(response, HttpStatus.OK, ret, token, null);
	}

	/**
	 * {@inheritDoc}
	 *
	 * Called when authentication failed.
	 */
	@Override
	public void onAuthenticationFailure(final HttpServletRequest request, final HttpServletResponse response,
			final AuthenticationException exception) throws IOException, ServletException {

		final UserStatus ret = new UserStatus();
		ret.setSessionId(request.getSession().getId());

		final CsrfToken token = (CsrfToken) request.getAttribute(CsrfToken.class.getName());

		sendResponse(response, HttpStatus.UNAUTHORIZED, ret, token, exception);
	}

	/**
	 * {@inheritDoc}
	 *
	 * Called when access to resource is denied.
	 */
	@Override
	public void handle(final HttpServletRequest request, final HttpServletResponse response,
			final AccessDeniedException exception) throws IOException, ServletException {

		onAuthenticationFailure(request, response,
				new InsufficientAuthenticationException(
						StringUtils.isNotBlank(exception.getMessage()) ? exception.getMessage() : "Not authenticated",
						exception));
	}

	////////////////////////////////////////////////////////////////////////////////////////
	// logout
	////////////////////////////////////////////////////////////////////////////////////////

	/**
	 * {@inheritDoc}
	 *
	 * Called when logout was successful.
	 */
	@Override
	public void onLogoutSuccess(final HttpServletRequest request, final HttpServletResponse response,
			final Authentication authentication) throws IOException, ServletException {

		final UserStatus ret = new UserStatus();
		ret.setRedirectUrl("/");
		ret.setSessionId(request.getSession().getId());

		final CsrfToken token = csrfTokenRepository.generateToken(request);

		sendResponse(response, HttpStatus.OK, ret, token, null);
	}

	////////////////////////////////////////////////////////////////////////////////////////
	// helper methods
	////////////////////////////////////////////////////////////////////////////////////////

	protected String getUsername(final Authentication authentication) {
		String username = "";

		if (authentication.getDetails() instanceof User) {
			username = ((User) authentication.getDetails()).getUsername();
		} else if (authentication.getPrincipal() instanceof String) {
			username = (String) authentication.getPrincipal();
		}

		if (StringUtils.isBlank(username)) {
			username = authentication.getName();
		}

		return username;
	}

	protected void sendResponse(final HttpServletResponse response, final HttpStatus httpStatusCode,
			final UserStatus payload, final CsrfToken token, final AuthenticationException exception)
			throws IOException {

		// set csrf token to header
		response.setHeader(token.getHeaderName(), token.getToken());

		response.setStatus(httpStatusCode.value());
		response.setContentType(MediaType.APPLICATION_JSON_VALUE);

		final DataResponse ret = DataResponse.ok().withPayload(payload);

		if (exception != null) {
			ret.withError("login.error", exception.getMessage());
		}

		try {
			response.getWriter().println(serializationService.toJson(ret));
		} catch (final SerializationException e) {
			throw new IOException("Could not serialize authentication response payload", e);
		}

		response.getWriter().flush();
	}

	protected String getCsrfToken(final HttpServletRequest request) {
		return csrfTokenRepository.loadToken(request).getToken();
	}
}

@@ -1406,24 +1406,148 @@
 ionService;%0A
+import io.spotnext.itemtype.core.beans.SerializationConfiguration;%0Aimport io.spotnext.itemtype.core.enumeration.DataFormat;%0A
 import io.sp
@@ -1665,19 +1665,16 @@
 ogether.
-%0A *
  It is p
@@ -2103,24 +2103,16 @@
 eritDoc%7D
-%0A%09 *%0A%09 *
  Aborts 
@@ -2172,20 +2172,16 @@
 ends the
-%0A%09 *
  www-aut
@@ -2737,32 +2737,24 @@
 @inheritDoc%7D
-%0A%09 *%0A%09 *
  Called when
@@ -3326,32 +3326,24 @@
 @inheritDoc%7D
-%0A%09 *%0A%09 *
  Called when
@@ -3851,32 +3851,24 @@
 @inheritDoc%7D
-%0A%09 *%0A%09 *
  Called when
@@ -4518,16 +4518,8 @@
 Doc%7D
-%0A%09 *%0A%09 *
  Cal
@@ -6218,16 +6218,126 @@
 );%0A%09%09%7D%0A%0A
+%09%09SerializationConfiguration config = new SerializationConfiguration();%0A%09%09config.setFormat(DataFormat.JSON);%0A%0A
 %09%09try %7B%0A
@@ -6393,15 +6393,26 @@
 ice.
-toJson(
+serialize(config, 
 ret)

build fix