/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* 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 org.keycloak.testsuite.arquillian.undertow;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.Servlet;
import io.undertow.servlet.api.DeploymentInfo;
import io.undertow.servlet.api.FilterInfo;
import io.undertow.servlet.api.LoginConfig;
import io.undertow.servlet.api.SecurityConstraint;
import io.undertow.servlet.api.SecurityInfo;
import io.undertow.servlet.api.ServletInfo;
import io.undertow.servlet.api.WebResourceCollection;
import org.jboss.logging.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Simple web.xml parser just to handle our test deployments
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
class SimpleWebXmlParser {
private static final Logger log = Logger.getLogger(SimpleWebXmlParser.class);
void parseWebXml(Document webXml, DeploymentInfo di) {
try {
DocumentWrapper document = new DocumentWrapper(webXml);
// SERVLETS
Map<String, String> servletMappings = new HashMap<>();
List<ElementWrapper> sm = document.getElementsByTagName("servlet-mapping");
for (ElementWrapper mapping : sm) {
String servletName = mapping.getElementByTagName("servlet-name").getText();
String path = mapping.getElementByTagName("url-pattern").getText();
servletMappings.put(servletName, path);
}
List<ElementWrapper> servlets = document.getElementsByTagName("servlet");
for (ElementWrapper servlet : servlets) {
String servletName = servlet.getElementByTagName("servlet-name").getText();
String servletClass = servlet.getElementByTagName("servlet-class").getText();
Class<? extends Servlet> servletClazz = (Class<? extends Servlet>) Class.forName(servletClass);
ServletInfo undertowServlet = new ServletInfo(servletName, servletClazz);
if (servletMappings.containsKey(servletName)) {
undertowServlet.addMapping(servletMappings.get(servletName));
di.addServlet(undertowServlet);
} else {
log.warnf("Missing servlet-mapping for '%s'", servletName);
}
}
// FILTERS
Map<String, String> filterMappings = new HashMap<>();
List<ElementWrapper> fm = document.getElementsByTagName("filter-mapping");
for (ElementWrapper mapping : fm) {
String filterName = mapping.getElementByTagName("filter-name").getText();
String path = mapping.getElementByTagName("url-pattern").getText();
filterMappings.put(filterName, path);
}
List<ElementWrapper> filters = document.getElementsByTagName("filter");
for (ElementWrapper filter : filters) {
String filterName = filter.getElementByTagName("filter-name").getText();
String filterClass = filter.getElementByTagName("filter-class").getText();
Class<? extends Filter> filterClazz = (Class<? extends Filter>) Class.forName(filterClass);
FilterInfo undertowFilter = new FilterInfo(filterName, filterClazz);
List<ElementWrapper> initParams = filter.getElementsByTagName("init-param");
for (ElementWrapper initParam : initParams) {
String paramName = initParam.getElementByTagName("param-name").getText();
String paramValue = initParam.getElementByTagName("param-value").getText();
undertowFilter.addInitParam(paramName, paramValue);
}
di.addFilter(undertowFilter);
if (filterMappings.containsKey(filterName)) {
di.addFilterUrlMapping(filterName, filterMappings.get(filterName), DispatcherType.REQUEST);
} else {
log.warnf("Missing filter-mapping for '%s'", filterName);
}
}
// CONTEXT PARAMS
List<ElementWrapper> contextParams = document.getElementsByTagName("context-param");
for (ElementWrapper param : contextParams) {
String paramName = param.getElementByTagName("param-name").getText();
String paramValue = param.getElementByTagName("param-value").getText();
di.addInitParameter(paramName, paramValue);
}
// ROLES
List<ElementWrapper> securityRoles = document.getElementsByTagName("security-role");
for (ElementWrapper sr : securityRoles) {
String roleName = sr.getElementByTagName("role-name").getText();
di.addSecurityRole(roleName);
}
// SECURITY CONSTRAINTS
List<ElementWrapper> secConstraints = document.getElementsByTagName("security-constraint");
for (ElementWrapper constraint : secConstraints) {
String urlPattern = constraint.getElementByTagName("web-resource-collection")
.getElementByTagName("url-pattern")
.getText();
ElementWrapper authCsnt = constraint.getElementByTagName("auth-constraint");
String roleName = authCsnt==null ? null : authCsnt
.getElementByTagName("role-name")
.getText();
SecurityConstraint undertowConstraint = new SecurityConstraint();
WebResourceCollection collection = new WebResourceCollection();
collection.addUrlPattern(urlPattern);
undertowConstraint.addWebResourceCollection(collection);
if (roleName != null) {
undertowConstraint.addRoleAllowed(roleName);
} else {
undertowConstraint.setEmptyRoleSemantic(SecurityInfo.EmptyRoleSemantic.PERMIT);
}
di.addSecurityConstraint(undertowConstraint);
}
// LOGIN CONFIG
ElementWrapper loginCfg = document.getElementByTagName("login-config");
if (loginCfg != null) {
String mech = loginCfg.getElementByTagName("auth-method").getText();
String realmName = loginCfg.getElementByTagName("realm-name").getText();
ElementWrapper form = loginCfg.getElementByTagName("form-login-config");
if (form != null) {
String loginPage = form.getElementByTagName("form-login-page").getText();
String errorPage = form.getElementByTagName("form-error-page").getText();
di.setLoginConfig(new LoginConfig(mech, realmName, loginPage, errorPage));
} else {
di.setLoginConfig(new LoginConfig(realmName).addFirstAuthMethod(mech));
}
}
} catch (ClassNotFoundException cnfe) {
throw new RuntimeException(cnfe);
}
}
private static abstract class XmlWrapper {
abstract List<ElementWrapper> getElementsByTagName(String tagName);
abstract ElementWrapper getElementByTagName(String tagName);
List<ElementWrapper> getElementsFromNodeList(NodeList nl) {
List<ElementWrapper> result = new LinkedList<>();
for (int i=0; i<nl.getLength() ; i++) {
Node node = nl.item(i);
if (node instanceof Element) {
result.add(new ElementWrapper((Element) node));
}
}
return result;
}
ElementWrapper getElementFromNodeList(NodeList nl) {
if (nl.getLength() > 0) {
return new ElementWrapper((Element) nl.item(0));
} else {
return null;
}
}
}
private static class ElementWrapper extends XmlWrapper {
private final Element element;
public ElementWrapper(Element element) {
this.element = element;
}
@Override
public List<ElementWrapper> getElementsByTagName(String tagName) {
NodeList nl = element.getElementsByTagName(tagName);
return getElementsFromNodeList(nl);
}
@Override
public ElementWrapper getElementByTagName(String tagName) {
NodeList nl = element.getElementsByTagName(tagName);
return getElementFromNodeList(nl);
}
public String getText() {
return this.element.getTextContent();
}
}
private static class DocumentWrapper extends XmlWrapper {
private final Document document;
public DocumentWrapper(Document document) {
this.document = document;
}
@Override
List<ElementWrapper> getElementsByTagName(String tagName) {
NodeList nl = document.getElementsByTagName(tagName);
return getElementsFromNodeList(nl);
}
@Override
ElementWrapper getElementByTagName(String tagName) {
NodeList nl = document.getElementsByTagName(tagName);
return getElementFromNodeList(nl);
}
}
}