All Downloads are FREE. Search and download functionalities are using the official Maven repository.

nl.nn.adapterframework.lifecycle.servlets.ServletConfiguration Maven / Gradle / Ivy

There is a newer version: 7.9.5
Show newest version
/*
   Copyright 2022-2023 WeAreFrank!

   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 nl.nn.adapterframework.lifecycle.servlets;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.annotation.Nonnull;
import javax.servlet.annotation.ServletSecurity.TransportGuarantee;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;
import nl.nn.adapterframework.lifecycle.DynamicRegistration;
import nl.nn.adapterframework.lifecycle.DynamicRegistration.Servlet;
import nl.nn.adapterframework.util.EnumUtils;

//servlets:
//  IAF-API:
//    transportGuarantee: NONE
//    securityRoles:
//      - IbisObserver
//      - IbisDataAdmin
//      - IbisAdmin
//      - IbisTester
//    urlMapping: iaf/api/*
//    loadOnStartup: 0
//    authenticator: myAuthenticatorID
@Log4j2
public class ServletConfiguration implements InitializingBean, EnvironmentAware {

	private static final char SLASH = '/';
	private @Getter String name;
	private List securityRoles = Collections.emptyList();
	private @Getter List urlMapping;
	private @Getter @Setter int loadOnStartup = -1;
	private @Getter @Setter boolean enabled = true;
	private @Getter TransportGuarantee transportGuarantee;
	private @Getter String authenticatorName = null;
	private @Getter javax.servlet.Servlet servlet;
	private @Setter Environment environment;
	private @Getter Map initParameters = new LinkedHashMap<>();

	@Override
	public void afterPropertiesSet() {
		defaultSecuritySettings();
	}

	public void setSecurityRoles(String[] accessGrantingRoles) {
		if(accessGrantingRoles != null) {
			this.securityRoles = Arrays.asList(accessGrantingRoles);
		}
	}

	@Nonnull
	public List getSecurityRoles() {
		return securityRoles;
	}

	public void setName(String servletName) {
		this.name = servletName;
		if(this.name.contains(" ")) {
			throw new IllegalArgumentException("unable to instantiate servlet, servlet name may not contain spaces");
		}
	}

	/** Convenience method to easily register a dynamic Frank servlet. */
	public void fromServlet(Servlet servlet) {
		setName(servlet.getName());
		setUrlMapping(servlet.getUrlMapping());
		setSecurityRoles(servlet.getAccessGrantingRoles());
		setLoadOnStartup(servlet.loadOnStartUp());
		setEnabled(servlet.isEnabled());
		setServlet(servlet);

		if(servlet instanceof DynamicRegistration.ServletWithParameters) {
			Map initParams = ((DynamicRegistration.ServletWithParameters) servlet).getParameters();
			initParams.entrySet().stream().forEach(e -> addInitParameter(e.getKey(), e.getValue()));
		}

		loadProperties();
	}

	public void setServlet(javax.servlet.Servlet servlet) {
		this.servlet = servlet;
	}

	public void addInitParameter(String name, String value) {
		this.initParameters.put(name, value);
	}

	public boolean isAuthenticationEnabled() {
		return !securityRoles.isEmpty() && !"NONE".equals(authenticatorName);
	}

	private void defaultSecuritySettings() {
		transportGuarantee = SecuritySettings.getDefaultTransportGuarantee();
		AuthenticationType defaultType = SecuritySettings.isWebSecurityEnabled() ? AuthenticationType.CONTAINER : AuthenticationType.NONE;
		authenticatorName = defaultType.name();
	}

	/**
	 * Overwrites servlet defaults with properties.
	 */
	public void loadProperties() {
		String propertyPrefix = "servlet."+name+".";

		this.enabled = environment.getProperty(propertyPrefix+"enabled", boolean.class, enabled);
		configureServletSecurity(propertyPrefix);
		String constraintType = environment.getProperty(propertyPrefix+"transportGuarantee");
		if(StringUtils.isNotEmpty(constraintType)) {
			this.transportGuarantee = EnumUtils.parse(TransportGuarantee.class, constraintType);
		}
		this.loadOnStartup = environment.getProperty(propertyPrefix+"loadOnStartup", int.class, loadOnStartup);
		String mapping = environment.getProperty(propertyPrefix+"urlMapping");
		if(StringUtils.isNotEmpty(mapping)) {
			setUrlMapping(mapping);
		}
		this.authenticatorName = environment.getProperty(propertyPrefix+"authenticator", authenticatorName);
	}

	private void configureServletSecurity(String propertyPrefix) {
		String roleNames = environment.getProperty(propertyPrefix+"securityRoles");
		if(environment.containsProperty(propertyPrefix+"securityroles")) { //Deprecated warning
			log.warn("property ["+propertyPrefix+"securityroles] has been replaced with ["+propertyPrefix+"securityRoles"+"]");
			roleNames = environment.getProperty(propertyPrefix+"securityroles");
		}

		if(StringUtils.isNotEmpty(roleNames)) {
			String[] rolesCopy = roleNames.split(",");
			securityRoles = Arrays.asList(rolesCopy);
		}
	}

	private void setUrlMapping(List urlMappings) {
		if(urlMappings == null || urlMappings.isEmpty()) {
			throw new IllegalStateException("servlet must have an URL to map to");
		}

		this.urlMapping = urlMappings.stream().filter(StringUtils::isNotBlank).collect(Collectors.toList());
	}

	public void setUrlMapping(String urlMappingArray) {
		String[] urlMappingsCopy = new String[0];
		if(StringUtils.isNotEmpty(urlMappingArray)) {
			urlMappingsCopy = urlMappingArray.split(",");
		}

		List mappings = new ArrayList<>();
		for(final String rawMapping : urlMappingsCopy) {
			String mapping = rawMapping.trim();
			if(StringUtils.isBlank(mapping)) continue;
			if("*".equals(mapping)) mapping = "/*";

			char firstChar = mapping.charAt(0);
			if(firstChar == '!' && (mapping.charAt(1) != SLASH || mapping.charAt(mapping.length()-1) == '*')) {
				throw new IllegalStateException("when excluding an URL you it must start with '!/' and may not end with a wildcard");
			}
			if(firstChar != SLASH && firstChar != '*' && firstChar != '!') { //Add a conditional slash
				mapping = "/"+mapping;
			}
			log.debug("converted raw mapping [{}] to [{}]", rawMapping, mapping);
			mappings.add(mapping);
		}

		setUrlMapping(mappings);
	}

	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder(" servlet ["+name+"]");
		builder.append(" url(s) "+urlMapping);
		builder.append(" loadOnStartup ["+loadOnStartup+"]");
		builder.append(" protocol "+(transportGuarantee==TransportGuarantee.CONFIDENTIAL?"[HTTPS]":"[HTTP]"));
		builder.append(" authenticatior ["+authenticatorName+"]");

		if(isAuthenticationEnabled()) {
			builder.append(" roles "+getSecurityRoles());
		} else {
			builder.append(" with no authentication enabled!");
		}
		return builder.toString();
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy