package org.ihtsdo.buildcloud.security;

import org.ihtsdo.buildcloud.entity.User;
import org.ihtsdo.buildcloud.service.AuthenticationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.DatatypeConverter;
import java.io.IOException;

public class SecurityFilter implements Filter {

	private AuthenticationService authenticationService;
	private static final Logger LOGGER = LoggerFactory.getLogger(SecurityFilter.class);

	public void init(FilterConfig config) throws ServletException {
		ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(config.getServletContext());
		authenticationService = applicationContext.getBean(AuthenticationService.class);
	}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
		SecurityHelper.clearSubject();

		final HttpServletRequest httpRequest = (HttpServletRequest) request;
		final HttpServletResponse httpResponse = (HttpServletResponse) response;
		final String authHeader = httpRequest.getHeader("Authorization");

		String pathInfo = httpRequest.getPathInfo();
		String requestMethod = httpRequest.getMethod();
		LOGGER.debug("pathInfo: '{}'", pathInfo);

		if (pathInfo.startsWith("/login")) {
			// Trying to log in
			chain.doFilter(request, response);
		} else if (authHeader == null && requestMethod.equals("GET")) {
			// An anonymous GET
			User anonymousSubject = authenticationService.getAnonymousSubject();
			SecurityHelper.setSubject(anonymousSubject);
			chain.doFilter(request, response);
		} else if (authHeader != null){
			User authenticatedSubject = null;
			if (authHeader != null) {
				final int index = authHeader.indexOf(' ');
				if (index > 0) {
					String credsString = new String(DatatypeConverter.parseBase64Binary(authHeader.substring(index)));
					String[] credentials = credsString.split(":");

					if (credentials != null && credentials.length > 0) {
						String authenticationToken = credentials[0];
						authenticatedSubject = authenticationService.getAuthenticatedSubject(authenticationToken);
					}
				}
			}

			if (authenticatedSubject != null) {
				try {
					// Bind authenticated subject/user to thread
					SecurityHelper.setSubject(authenticatedSubject);

					chain.doFilter(request, response);
				} finally {
					SecurityHelper.clearSubject();
				}
			}
			httpResponse.setHeader("WWW-Authenticate", "Basic realm=\"API Authentication Token\"");
			httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
		} else {
			httpResponse.setHeader("WWW-Authenticate", "Basic realm=\"API Authentication Token\"");
			httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
		}
	}

	public void destroy() {
	}

}

@@ -1352,16 +1352,57 @@
 ation%22);
+%0A%09%09boolean authenticationRequired = true;
 %0A%0A%09%09Stri
@@ -1876,32 +1876,67 @@
 est, response);%0A
+%09%09%09authenticationRequired = false;%0A
 %09%09%7D else if (aut
@@ -2504,24 +2504,60 @@
  != null) %7B%0A
+%09%09%09%09authenticationRequired = false;%0A
 %09%09%09%09try %7B%0A%09%09
@@ -2765,172 +2765,47 @@
 %09%09%09%7D
+ 
 %0A%09%09
-%09httpResponse.setHeader(%22WWW-Authenticate%22, %22Basic realm=%5C%22API Authentication Token%5C%22%22);%0A%09%09%09httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);%0A%09%09%7D else
+%7D %0A%09%09%0A%09%09if (authenticationRequired)
  %7B%0A%09
@@ -2958,20 +2958,23 @@
 RIZED);%0A
-
 %09%09%7D%0A
+%09%09%0A
 %09%7D%0A%0A%09pub

Fix issue with API randomly failing basic auth.