<commit_before>package com.krishagni.catissueplus.rest.filter;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.HttpHeaders;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.codec.Base64;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.filter.GenericFilterBean;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.krishagni.catissueplus.core.administrative.domain.User;
import com.krishagni.catissueplus.core.audit.domain.UserApiCallLog;
import com.krishagni.catissueplus.core.audit.services.AuditService;
import com.krishagni.catissueplus.core.auth.domain.AuthToken;
import com.krishagni.catissueplus.core.auth.domain.LoginAuditLog;
import com.krishagni.catissueplus.core.auth.domain.UserRequestData;
import com.krishagni.catissueplus.core.auth.events.LoginDetail;
import com.krishagni.catissueplus.core.auth.events.TokenDetail;
import com.krishagni.catissueplus.core.auth.services.UserAuthenticationService;
import com.krishagni.catissueplus.core.auth.services.UserRequestDataProvider;
import com.krishagni.catissueplus.core.common.events.RequestEvent;
import com.krishagni.catissueplus.core.common.events.ResponseEvent;
import com.krishagni.catissueplus.core.common.service.ConfigChangeListener;
import com.krishagni.catissueplus.core.common.service.ConfigurationService;
import com.krishagni.catissueplus.core.common.util.AuthUtil;
import com.krishagni.catissueplus.core.common.util.ConfigUtil;
import com.krishagni.catissueplus.core.common.util.Utility;
import com.krishagni.catissueplus.rest.RestErrorController;

public class AuthTokenFilter extends GenericFilterBean implements InitializingBean {
	private static final String OS_CLIENT_HDR = "X-OS-API-CLIENT";

	private static final String BASIC_AUTH = "Basic ";
	
	private Set<String> allowedOrigins;
	
	private UserAuthenticationService authService;
	
	private Map<String, List<String>> excludeUrls = new HashMap<>();

	private AuditService auditService;

	private ConfigurationService cfgSvc;

	private List<UserRequestDataProvider> userRequestDataProviders = new ArrayList<>();

	public void setAuthService(UserAuthenticationService authService) {
		this.authService = authService;
	}

	public void setCfgSvc(ConfigurationService cfgSvc) {
		this.cfgSvc = cfgSvc;
	}

	public void setExcludeUrls(Map<String, List<String>> excludeUrls) {
		this.excludeUrls = excludeUrls;
	}

	public void addExcludeUrl(String method, String resourceUrl) {
		addUrl(excludeUrls, method, resourceUrl);
	}

	public void setAuditService(AuditService auditService) {
		this.auditService = auditService;
	}

	public void addUserRequestDataProvider(UserRequestDataProvider provider) {
		userRequestDataProviders.add(provider);
	}

	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
	throws IOException {
		if (!(req instanceof HttpServletRequest)) {
			throw new IllegalAccessError("Unknown protocol request");
		}

		try {
			doFilter0(req, resp, chain);
		} catch (Exception e) {
			sendError((HttpServletRequest) req, (HttpServletResponse) resp, e);
		}
	}

	@Override
	public void afterPropertiesSet()
	throws ServletException {
		super.afterPropertiesSet();
		cfgSvc.registerChangeListener("common", new ConfigChangeListener() {
			@Override
			public void onConfigChange(String name, String value) {
				if (!"allowed_req_origins".equals(name)) {
					return;
				}

				allowedOrigins = getAllowedOrigins(value);
			}
		});
	}

	private void doFilter0(ServletRequest req, ServletResponse resp, FilterChain chain)
	throws IOException, ServletException {
		HttpServletRequest httpReq = (HttpServletRequest)req;
		HttpServletResponse httpResp = (HttpServletResponse)resp;

		String origin = httpReq.getHeader("Origin");
		if (!isOriginAllowed(origin)) {
			httpResp.sendError(
				HttpServletResponse.SC_METHOD_NOT_ALLOWED,
				"Requests from the origin server "  + origin + " not allowed");
			return;
		}

		if (StringUtils.isNotBlank(origin)) {
			httpResp.setHeader("Access-Control-Allow-Origin", origin);
		}

		httpResp.setHeader("Access-Control-Allow-Credentials", "true");
		httpResp.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE, PATCH, OPTIONS");
		httpResp.setHeader("Access-Control-Allow-Headers", "Origin, Accept, Content-Type, X-OS-API-TOKEN, X-OS-API-CLIENT, X-OS-IMPERSONATE-USER, X-OS-CLIENT-TZ, X-OS-SURVEY-TOKEN");
		httpResp.setHeader("Access-Control-Expose-Headers", "Content-Disposition, Content-Length, Content-Type");

		httpResp.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
		httpResp.setHeader("Pragma", "no-cache");
		httpResp.setDateHeader("Expires", 0);

		if (httpReq.getMethod().equalsIgnoreCase("options")) {
			httpResp.setStatus(HttpServletResponse.SC_OK);
			return;
		}

		User user = null;
		String authToken = AuthUtil.getAuthTokenFromHeader(httpReq);
		if (authToken == null) {
			authToken = AuthUtil.getTokenFromCookie(httpReq);
		}
		
		LoginAuditLog loginAuditLog = null;
		if (authToken != null) {
			TokenDetail tokenDetail = new TokenDetail();
			tokenDetail.setToken(authToken);
			tokenDetail.setIpAddress(Utility.getRemoteAddress(httpReq));

			ResponseEvent<AuthToken> atResp = authService.validateToken(new RequestEvent<>(tokenDetail));
			atResp.throwErrorIfUnsuccessful();

			user = atResp.getPayload().getUser();
			loginAuditLog = atResp.getPayload().getLoginAuditLog();
		} else if (httpReq.getHeader(HttpHeaders.AUTHORIZATION) != null) {
			AuthToken token = doBasicAuthentication(httpReq, httpResp);
			if (token != null) {
				user = token.getUser();
				loginAuditLog = token.getLoginAuditLog();
			}
		}

		httpReq.setAttribute("user", user);
		setupReqDataProviders(httpReq, httpResp);
		if (user == null) {
			user = UserRequestData.getInstance().getUser();
		}

		if (user == null) {
			String clientHdr = httpReq.getHeader(OS_CLIENT_HDR);
			if (clientHdr != null && clientHdr.equals("webui")) {
				setUnauthorizedResp(req, resp, chain, false);
			} else {
				setRequireAuthResp(req, resp, chain);
			}
<commit_msg>OPSMN-5568: Return HTTP 401 instead of HTTP 400 when an invalid token or API calls from unrecognised IPs are made.<commit_after>package com.krishagni.catissueplus.rest.filter;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.HttpHeaders;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.codec.Base64;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.filter.GenericFilterBean;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.krishagni.catissueplus.core.administrative.domain.User;
import com.krishagni.catissueplus.core.audit.domain.UserApiCallLog;
import com.krishagni.catissueplus.core.audit.services.AuditService;
import com.krishagni.catissueplus.core.auth.domain.AuthToken;
import com.krishagni.catissueplus.core.auth.domain.LoginAuditLog;
import com.krishagni.catissueplus.core.auth.domain.UserRequestData;
import com.krishagni.catissueplus.core.auth.events.LoginDetail;
import com.krishagni.catissueplus.core.auth.events.TokenDetail;
import com.krishagni.catissueplus.core.auth.services.UserAuthenticationService;
import com.krishagni.catissueplus.core.auth.services.UserRequestDataProvider;
import com.krishagni.catissueplus.core.common.events.RequestEvent;
import com.krishagni.catissueplus.core.common.events.ResponseEvent;
import com.krishagni.catissueplus.core.common.service.ConfigChangeListener;
import com.krishagni.catissueplus.core.common.service.ConfigurationService;
import com.krishagni.catissueplus.core.common.util.AuthUtil;
import com.krishagni.catissueplus.core.common.util.ConfigUtil;
import com.krishagni.catissueplus.core.common.util.Utility;
import com.krishagni.catissueplus.rest.RestErrorController;

public class AuthTokenFilter extends GenericFilterBean implements InitializingBean {
	private static final String OS_CLIENT_HDR = "X-OS-API-CLIENT";

	private static final String BASIC_AUTH = "Basic ";
	
	private Set<String> allowedOrigins;
	
	private UserAuthenticationService authService;
	
	private Map<String, List<String>> excludeUrls = new HashMap<>();

	private AuditService auditService;

	private ConfigurationService cfgSvc;

	private List<UserRequestDataProvider> userRequestDataProviders = new ArrayList<>();

	public void setAuthService(UserAuthenticationService authService) {
		this.authService = authService;
	}

	public void setCfgSvc(ConfigurationService cfgSvc) {
		this.cfgSvc = cfgSvc;
	}

	public void setExcludeUrls(Map<String, List<String>> excludeUrls) {
		this.excludeUrls = excludeUrls;
	}

	public void addExcludeUrl(String method, String resourceUrl) {
		addUrl(excludeUrls, method, resourceUrl);
	}

	public void setAuditService(AuditService auditService) {
		this.auditService = auditService;
	}

	public void addUserRequestDataProvider(UserRequestDataProvider provider) {
		userRequestDataProviders.add(provider);
	}

	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
	throws IOException {
		if (!(req instanceof HttpServletRequest)) {
			throw new IllegalAccessError("Unknown protocol request");
		}

		try {
			doFilter0(req, resp, chain);
		} catch (Exception e) {
			sendError((HttpServletRequest) req, (HttpServletResponse) resp, e);
		}
	}

	@Override
	public void afterPropertiesSet()
	throws ServletException {
		super.afterPropertiesSet();
		cfgSvc.registerChangeListener("common", new ConfigChangeListener() {
			@Override
			public void onConfigChange(String name, String value) {
				if (!"allowed_req_origins".equals(name)) {
					return;
				}

				allowedOrigins = getAllowedOrigins(value);
			}
		});
	}

	private void doFilter0(ServletRequest req, ServletResponse resp, FilterChain chain)
	throws IOException, ServletException {
		HttpServletRequest httpReq = (HttpServletRequest)req;
		HttpServletResponse httpResp = (HttpServletResponse)resp;

		String origin = httpReq.getHeader("Origin");
		if (!isOriginAllowed(origin)) {
			httpResp.sendError(
				HttpServletResponse.SC_METHOD_NOT_ALLOWED,
				"Requests from the origin server "  + origin + " not allowed");
			return;
		}

		if (StringUtils.isNotBlank(origin)) {
			httpResp.setHeader("Access-Control-Allow-Origin", origin);
		}

		httpResp.setHeader("Access-Control-Allow-Credentials", "true");
		httpResp.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE, PATCH, OPTIONS");
		httpResp.setHeader("Access-Control-Allow-Headers", "Origin, Accept, Content-Type, X-OS-API-TOKEN, X-OS-API-CLIENT, X-OS-IMPERSONATE-USER, X-OS-CLIENT-TZ, X-OS-SURVEY-TOKEN");
		httpResp.setHeader("Access-Control-Expose-Headers", "Content-Disposition, Content-Length, Content-Type");

		httpResp.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
		httpResp.setHeader("Pragma", "no-cache");
		httpResp.setDateHeader("Expires", 0);

		if (httpReq.getMethod().equalsIgnoreCase("options")) {
			httpResp.setStatus(HttpServletResponse.SC_OK);
			return;
		}

		User user = null;
		String authToken = AuthUtil.getAuthTokenFromHeader(httpReq);
		if (authToken == null) {
			authToken = AuthUtil.getTokenFromCookie(httpReq);
		}
		
		LoginAuditLog loginAuditLog = null;
		if (authToken != null) {
			TokenDetail tokenDetail = new TokenDetail();
			tokenDetail.setToken(authToken);
			tokenDetail.setIpAddress(Utility.getRemoteAddress(httpReq));

			ResponseEvent<AuthToken> atResp = authService.validateToken(new RequestEvent<>(tokenDetail));
			if (atResp.isSuccessful()) {
				user = atResp.getPayload().getUser();
				loginAuditLog = atResp.getPayload().getLoginAuditLog();
			}
		} else if (httpReq.getHeader(HttpHeaders.AUTHORIZATION) != null) {
			AuthToken token = doBasicAuthentication(httpReq, httpResp);
			if (token != null) {
				user = token.getUser();
				loginAuditLog = token.getLoginAuditLog();
			}
		}

		httpReq.setAttribute("user", user);
		setupReqDataProviders(httpReq, httpResp);
		if (user == null) {
			user = UserRequestData.getInstance().getUser();
		}

		if (user == null) {
			String clientHdr = httpReq.getHeader(OS_CLIENT_HDR);
			if (clientHdr != null && clientHdr.equals("webui")) {
				setUnauthorizedResp(req, resp, chain, false);
			} else {
				setRequireAuthResp(req, resp, chain);
			}

{'fraction_non_alphanumeric': 0.11037783740662847, 'fraction_numerical': 0.0015954746537094786, 'mean_word_length': 5.71699951290794, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3141736', 'n_tokens_mistral': 4564, 'n_tokens_neox': 4222, 'n_words': 762}