// Copyright 2006 Google Inc. // // 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 com.google.enterprise.connector.servlet; import com.google.common.base.Strings; import com.google.common.collect.ImmutableMap; import com.google.enterprise.connector.logging.NDC; import com.google.enterprise.connector.manager.ConnectorStatus; import com.google.enterprise.connector.manager.Manager; import com.google.enterprise.connector.spi.AuthenticationIdentity; import com.google.enterprise.connector.spi.AuthenticationResponse; import com.google.enterprise.connector.spi.Principal; import com.google.enterprise.connector.spi.SimpleAuthenticationIdentity; import com.google.enterprise.connector.spi.SpiConstants; import com.google.enterprise.connector.spi.XmlUtils; import com.google.enterprise.connector.util.XmlParseUtil; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import java.io.IOException; import java.io.PrintWriter; import java.util.HashSet; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; /** * Admin servlet for Authenticate * */ public class Authenticate extends ConnectorManagerServlet { private static final Logger LOGGER = Logger.getLogger(Authenticate.class.getName()); @Override protected void processDoPost( String xmlBody, Manager manager, PrintWriter out) { NDC.append("AuthN"); handleDoPost(xmlBody, manager, out); } /** * Handler for doPost in order to do unit tests. * Writes credentials for connectors. * * @param xmlBody String the XML request body string * @param manager Manager * @param out PrintWriter where the response is written */ public static void handleDoPost( String xmlBody, Manager manager, PrintWriter out) { Element root = XmlParseUtil.parseAndGetRootElement( xmlBody, ServletUtil.XMLTAG_AUTHN_REQUEST); if (root == null) { ServletUtil.writeResponse( out, ConnectorMessageCode.ERROR_PARSING_XML_REQUEST); return; } NodeList credList = root.getElementsByTagName(ServletUtil.XMLTAG_AUTHN_CREDENTIAL); if (credList.getLength() == 0) { LOGGER.log(Level.WARNING, ServletUtil.LOG_RESPONSE_EMPTY_NODE); ServletUtil.writeResponse( out, ConnectorMessageCode.RESPONSE_EMPTY_NODE); return; } Set<String> requestedConnectors = null; NodeList connectorList = root.getElementsByTagName(ServletUtil.XMLTAG_CONNECTOR_NAME); if (connectorList.getLength() > 0) { requestedConnectors = new HashSet<String>(); for (int i = 0; i < connectorList.getLength(); i++) { String name = connectorList.item(i).getTextContent(); if (name != null) { requestedConnectors.add(name); } } } String username = XmlParseUtil.getFirstElementByTagName( (Element) credList.item(0), ServletUtil.XMLTAG_AUTHN_USERNAME); String domain = XmlParseUtil.getFirstElementByTagName( (Element) credList.item(0), ServletUtil.XMLTAG_AUTHN_DOMAIN); NDC.append(Strings.isNullOrEmpty(domain) ? username : (domain + "/" + username)); String password = XmlParseUtil.getOptionalElementByTagName( (Element) credList.item(0), ServletUtil.XMLTAG_AUTHN_PASSWORD); if (username == null || "".equals(password)) { ServletUtil.writeResponse( out, ConnectorMessageCode.RESPONSE_NULL_IDENTITY); return; } ServletUtil.writeRootTag(out, false); ServletUtil.writeXMLTag(out, 1, ServletUtil.XMLTAG_AUTHN_RESPONSE, false); AuthenticationIdentity identity = new SimpleAuthenticationIdentity(username, password, domain); handleEachConnector(requestedConnectors, identity, manager, out); ServletUtil.writeXMLTag(out, 1, ServletUtil.XMLTAG_AUTHN_RESPONSE, true); ServletUtil.writeRootTag(out, true); } /** * Writes a Success or Failure element for each requested connector * instance. */ private static void handleEachConnector(Set<String> requestedConnectors, AuthenticationIdentity identity, Manager manager, PrintWriter out) { for (ConnectorStatus connector : manager.getConnectorStatuses()) { String connectorName = connector.getName(); if (requestedConnectors != null && !requestedConnectors.contains(connectorName)) { continue; } NDC.pushAppend(connectorName); try { AuthenticationResponse response = manager.authenticate(connectorName, identity); if (response.isValid()) { ServletUtil.writeXMLTagWithAttrs( out, 2, ServletUtil.XMLTAG_SUCCESS, ImmutableMap.of(ServletUtil.XMLTAG_CONNECTOR_NAME, connectorName), false); ServletUtil.writeXMLElement(out, 3, ServletUtil.XMLTAG_IDENTITY, identity.getUsername()); // Add any returned groups that the user may belong to. if (response.getGroups() != null) { for (Object item : response.getGroups()) { Principal group = (item instanceof String) ? new Principal((String) item) : (Principal) item; out.append(ServletUtil.indentStr(3)); out.append('<').append(ServletUtil.XMLTAG_GROUP); if (group.getPrincipalType() == SpiConstants.PrincipalType.UNQUALIFIED) { // UNQUALIFIED is a special-case on the GSA to allow us to // prevent the GSA from mistakeningly finding a domain in the // principal name. XmlUtils.xmlAppendAttr( ServletUtil.XMLTAG_PRINCIPALTYPE_ATTRIBUTE, SpiConstants.PrincipalType.UNQUALIFIED.toString(), out); } if (!Strings.isNullOrEmpty(group.getNamespace())) { XmlUtils.xmlAppendAttr(ServletUtil.XMLTAG_NAMESPACE_ATTRIBUTE, group.getNamespace(), out); } out.append('>'); XmlUtils.xmlAppendAttrValue(group.getName(), out); XmlUtils.xmlAppendEndTag(ServletUtil.XMLTAG_GROUP, out); } } ServletUtil.writeXMLTag(out, 2, ServletUtil.XMLTAG_SUCCESS, true); } else if (identity.getPassword() == null) { // This is a group lookup request that failed. The GSA // requires that we return success here. ServletUtil.writeXMLTagWithAttrs( out, 2, ServletUtil.XMLTAG_SUCCESS, ImmutableMap.of(ServletUtil.XMLTAG_CONNECTOR_NAME, connectorName), true); } else { ServletUtil.writeXMLTagWithAttrs( out, 2, ServletUtil.XMLTAG_FAILURE, ImmutableMap.of(ServletUtil.XMLTAG_CONNECTOR_NAME, connectorName), true); } } catch (IOException e) { LOGGER.log(Level.WARNING, "Error writing Authentication Response", e); } finally { NDC.pop(); } } } }