[Yanel-commits] rev 28657 - in
public/yanel/trunk/src/webapp/src/java/org/wyona/yanel/servlet:
. security security/impl
michi at wyona.com
michi at wyona.com
Fri Nov 9 09:26:51 CET 2007
Author: michi
Date: 2007-11-09 09:26:50 +0100 (Fri, 09 Nov 2007)
New Revision: 28657
Added:
public/yanel/trunk/src/webapp/src/java/org/wyona/yanel/servlet/security/
public/yanel/trunk/src/webapp/src/java/org/wyona/yanel/servlet/security/WebAuthenticator.java
public/yanel/trunk/src/webapp/src/java/org/wyona/yanel/servlet/security/impl/
public/yanel/trunk/src/webapp/src/java/org/wyona/yanel/servlet/security/impl/DefaultWebAuthenticatorImpl.java
Log:
WebAuthenticator interface added
Added: public/yanel/trunk/src/webapp/src/java/org/wyona/yanel/servlet/security/WebAuthenticator.java
===================================================================
--- public/yanel/trunk/src/webapp/src/java/org/wyona/yanel/servlet/security/WebAuthenticator.java (rev 0)
+++ public/yanel/trunk/src/webapp/src/java/org/wyona/yanel/servlet/security/WebAuthenticator.java 2007-11-09 08:26:50 UTC (rev 28657)
@@ -0,0 +1,20 @@
+package org.wyona.yanel.servlet.security;
+
+import org.wyona.yanel.core.map.Map;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import java.io.IOException;
+
+/**
+ *
+ */
+public interface WebAuthenticator {
+
+ /**
+ *
+ */
+ public HttpServletResponse doAuthenticate(HttpServletRequest request, HttpServletResponse response, Map map, String reservedPrefix, String xsltLoginScreenDefault, String servletContextRealPath, String sslPort) throws ServletException, IOException, Exception;
+}
Added: public/yanel/trunk/src/webapp/src/java/org/wyona/yanel/servlet/security/impl/DefaultWebAuthenticatorImpl.java
===================================================================
--- public/yanel/trunk/src/webapp/src/java/org/wyona/yanel/servlet/security/impl/DefaultWebAuthenticatorImpl.java (rev 0)
+++ public/yanel/trunk/src/webapp/src/java/org/wyona/yanel/servlet/security/impl/DefaultWebAuthenticatorImpl.java 2007-11-09 08:26:50 UTC (rev 28657)
@@ -0,0 +1,335 @@
+package org.wyona.yanel.servlet.security.impl;
+
+import org.wyona.yanel.core.map.Map;
+import org.wyona.yanel.core.map.Realm;
+import org.wyona.yanel.servlet.IdentityMap;
+import org.wyona.yanel.servlet.YanelServlet;
+import org.wyona.yanel.servlet.security.WebAuthenticator;
+
+import org.wyona.security.core.api.Identity;
+import org.wyona.security.core.api.User;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.stream.StreamSource;
+
+import java.net.URL;
+
+import org.w3c.dom.Element;
+
+import org.apache.log4j.Category;
+
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
+
+/**
+ *
+ */
+public class DefaultWebAuthenticatorImpl implements WebAuthenticator {
+
+ private static Category log = Category.getInstance(DefaultWebAuthenticatorImpl.class);
+
+ /**
+ *
+ */
+ public HttpServletResponse doAuthenticate(HttpServletRequest request, HttpServletResponse response, Map map, String reservedPrefix, String xsltLoginScreenDefault, String servletContextRealPath, String sslPort) throws ServletException, IOException, Exception {
+ try {
+ Realm realm = map.getRealm(request.getServletPath());
+ String path = map.getPath(realm, request.getServletPath());
+ //Realm realm = map.getRealm(new Path(request.getServletPath()));
+
+ // HTML Form based authentication
+ String loginUsername = request.getParameter("yanel.login.username");
+ if(loginUsername != null) {
+ HttpSession session = request.getSession(true);
+ try {
+ User user = realm.getIdentityManager().getUserManager().getUser(loginUsername, true);
+ if (user != null && user.authenticate(request.getParameter("yanel.login.password"))) {
+ log.debug("Realm: " + realm);
+ IdentityMap identityMap = (IdentityMap)session.getAttribute(YanelServlet.IDENTITY_MAP_KEY);
+ if (identityMap == null) {
+ identityMap = new IdentityMap();
+ session.setAttribute(YanelServlet.IDENTITY_MAP_KEY, identityMap);
+ }
+ identityMap.put(realm.getID(), new Identity(user));
+ return null;
+ } else {
+ log.warn("Login failed: " + loginUsername);
+ getXHTMLAuthenticationForm(request, response, realm, "Login failed!", reservedPrefix, xsltLoginScreenDefault, servletContextRealPath, sslPort, map);
+ return response;
+ }
+ } catch (Exception e) {
+ log.warn("Login failed: " + loginUsername + " " + e);
+ getXHTMLAuthenticationForm(request, response, realm, "Login failed!", reservedPrefix, xsltLoginScreenDefault, servletContextRealPath, sslPort, map);
+ return response;
+ }
+ }
+
+ // Neutron-Auth based authentication
+ String yanelUsecase = request.getParameter("yanel.usecase");
+ if(yanelUsecase != null && yanelUsecase.equals("neutron-auth")) {
+ log.debug("Neutron Authentication ...");
+
+ String username = null;
+ String password = null;
+ String originalRequest = null;
+ DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder();
+ try {
+ Configuration config = builder.build(request.getInputStream());
+
+ Configuration originalRequestConfig = config.getChild("original-request");
+ originalRequest = originalRequestConfig.getAttribute("url", null);
+
+ Configuration[] paramConfig = config.getChildren("param");
+ for (int i = 0; i < paramConfig.length; i++) {
+ String paramName = paramConfig[i].getAttribute("name", null);
+ if (paramName != null) {
+ if (paramName.equals("username")) {
+ username = paramConfig[i].getValue();
+ } else if (paramName.equals("password")) {
+ password = paramConfig[i].getValue();
+ }
+ }
+ }
+ } catch(Exception e) {
+ log.warn(e);
+ }
+
+ log.debug("Username: " + username);
+
+ if (username != null) {
+ HttpSession session = request.getSession(true);
+ log.debug("Realm ID: " + realm.getID());
+ User user = realm.getIdentityManager().getUserManager().getUser(username, true);
+ if (user != null && user.authenticate(password)) {
+ log.info("Authentication successful: " + username);
+ IdentityMap identityMap = (IdentityMap)session.getAttribute(YanelServlet.IDENTITY_MAP_KEY);
+ if (identityMap == null) {
+ identityMap = new IdentityMap();
+ session.setAttribute(YanelServlet.IDENTITY_MAP_KEY, identityMap);
+ }
+ identityMap.put(realm.getID(), new Identity(user));
+
+ // TODO: send some XML content, e.g. <authentication-successful/>
+ response.setContentType("text/plain; charset=" + YanelServlet.DEFAULT_ENCODING);
+ response.setStatus(response.SC_OK);
+
+ PrintWriter writer = response.getWriter();
+ writer.print("Neutron Authentication Successful!");
+ return response;
+ } else {
+ log.warn("Neutron Authentication failed: " + username);
+
+ // TODO: Refactor this code with the one from doAuthenticate ...
+ log.debug("Original Request: " + originalRequest);
+
+ StringBuffer sb = new StringBuffer("");
+ sb.append("<?xml version=\"1.0\"?>");
+ sb.append("<exception xmlns=\"http://www.wyona.org/neutron/1.0\" type=\"authentication\">");
+ sb.append("<message>Authentication failed!</message>");
+ sb.append("<authentication>");
+ // TODO: ...
+ sb.append("<original-request url=\"" + YanelServlet.encodeXML(originalRequest) + "\"/>");
+ //sb.append("<original-request url=\"" + getRequestURLQS(request, null, true) + "\"/>");
+ //TODO: Also support https ...
+ // TODO: ...
+ sb.append("<login url=\"" + YanelServlet.encodeXML(originalRequest) + "&yanel.usecase=neutron-auth" + "\" method=\"POST\">");
+ //sb.append("<login url=\"" + getRequestURLQS(request, "yanel.usecase=neutron-auth", true) + "\" method=\"POST\">");
+ sb.append("<form>");
+ sb.append("<message>Enter username and password for \"" + realm.getName() + "\" at \"" + realm.getMountPoint() + "\"</message>");
+ sb.append("<param description=\"Username\" name=\"username\"/>");
+ sb.append("<param description=\"Password\" name=\"password\"/>");
+ sb.append("</form>");
+ sb.append("</login>");
+ // NOTE: Needs to be a full URL, because user might switch the server ...
+ // TODO: ...
+ sb.append("<logout url=\"" + YanelServlet.encodeXML(originalRequest) + "&yanel.usecase=logout" + "\" realm=\"" + realm.getName() + "\"/>");
+ sb.append("</authentication>");
+ sb.append("</exception>");
+
+ log.debug("Neutron-Auth response: " + sb);
+
+ response.setContentType("application/xml; charset=" + YanelServlet.DEFAULT_ENCODING);
+ response.setStatus(javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED);
+ response.setHeader("WWW-Authenticate", "NEUTRON-AUTH");
+
+ PrintWriter w = response.getWriter();
+ w.print(sb);
+ return response;
+ }
+ } else {
+ // TODO: Refactor resp. reuse response from above ...
+ log.warn("Neutron Authentication failed because username is NULL!");
+
+ StringBuffer sb = new StringBuffer("");
+ sb.append("<?xml version=\"1.0\"?>");
+ sb.append("<exception xmlns=\"http://www.wyona.org/neutron/1.0\" type=\"authentication\">");
+ sb.append("<message>Authentication failed because no username was sent!</message>");
+ sb.append("<authentication>");
+ // TODO: ...
+ sb.append("<original-request url=\"" + YanelServlet.encodeXML(originalRequest) + "\"/>");
+ //sb.append("<original-request url=\"" + getRequestURLQS(request, null, true) + "\"/>");
+ //TODO: Also support https ...
+ // TODO: ...
+ sb.append("<login url=\"" + YanelServlet.encodeXML(originalRequest) + "&yanel.usecase=neutron-auth" + "\" method=\"POST\">");
+ //sb.append("<login url=\"" + getRequestURLQS(request, "yanel.usecase=neutron-auth", true) + "\" method=\"POST\">");
+ sb.append("<form>");
+ sb.append("<message>Enter username and password for \"" + realm.getName() + "\" at \"" + realm.getMountPoint() + "\"</message>");
+ sb.append("<param description=\"Username\" name=\"username\"/>");
+ sb.append("<param description=\"Password\" name=\"password\"/>");
+ sb.append("</form>");
+ sb.append("</login>");
+ // NOTE: Needs to be a full URL, because user might switch the server ...
+ // TODO: ...
+ sb.append("<logout url=\"" + YanelServlet.encodeXML(originalRequest) + "&yanel.usecase=logout" + "\" realm=\"" + realm.getName() + "\"/>");
+ sb.append("</authentication>");
+ sb.append("</exception>");
+
+ response.setContentType("application/xml; charset=" + YanelServlet.DEFAULT_ENCODING);
+ response.setStatus(javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED);
+ response.setHeader("WWW-Authenticate", "NEUTRON-AUTH");
+
+ PrintWriter writer = response.getWriter();
+ writer.print(sb);
+ return response;
+ }
+ } else {
+ log.debug("Neutron Authentication successful.");
+ return null;
+ }
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ throw new ServletException(e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Custom XHTML Form for authentication
+ */
+ private void getXHTMLAuthenticationForm(HttpServletRequest request, HttpServletResponse response, Realm realm, String message, String reservedPrefix, String xsltLoginScreenDefault, String servletContextRealPath, String sslPort, Map map) throws ServletException, IOException {
+ String pathRelativeToRealm = request.getServletPath().replaceFirst(realm.getMountPoint(),"/");
+ String backToRealm = org.wyona.yanel.core.util.PathUtil.backToRealm(pathRelativeToRealm);
+
+ try {
+ org.w3c.dom.Document adoc = YanelServlet.getDocument(YanelServlet.NAMESPACE, "yanel-auth-screen");
+
+ Element rootElement = adoc.getDocumentElement();
+
+ if (message != null) {
+ Element messageElement = (Element) rootElement.appendChild(adoc.createElementNS(YanelServlet.NAMESPACE, "message"));
+ messageElement.appendChild(adoc.createTextNode(message));
+ }
+
+ Element requestElement = (Element) rootElement.appendChild(adoc.createElementNS(YanelServlet.NAMESPACE, "request"));
+ requestElement.setAttributeNS(YanelServlet.NAMESPACE, "urlqs", getRequestURLQS(request, null, true, map));
+
+ if (request.getQueryString() != null) {
+ requestElement.setAttributeNS(YanelServlet.NAMESPACE, "qs", request.getQueryString().replaceAll("&", "&"));
+ }
+
+ Element realmElement = (Element) rootElement.appendChild(adoc.createElementNS(YanelServlet.NAMESPACE, "realm"));
+ realmElement.setAttributeNS(YanelServlet.NAMESPACE, "name", realm.getName());
+ realmElement.setAttributeNS(YanelServlet.NAMESPACE, "mount-point", realm.getMountPoint().toString());
+
+ Element sslElement = (Element) rootElement.appendChild(adoc.createElementNS(YanelServlet.NAMESPACE, "ssl"));
+ if(sslPort != null) {
+ sslElement.setAttributeNS(YanelServlet.NAMESPACE, "status", "ON");
+ } else {
+ sslElement.setAttributeNS(YanelServlet.NAMESPACE, "status", "OFF");
+ }
+
+ String yanelFormat = request.getParameter("yanel.format");
+ if(yanelFormat != null && yanelFormat.equals("xml")) {
+ response.setContentType("application/xml; charset=" + YanelServlet.DEFAULT_ENCODING);
+ //OutputStream out = response.getOutputStream();
+ javax.xml.transform.TransformerFactory.newInstance().newTransformer().transform(new javax.xml.transform.dom.DOMSource(adoc), new javax.xml.transform.stream.StreamResult(response.getOutputStream()));
+ //out.close();
+ } else {
+ String mimeType = YanelServlet.patchMimeType("application/xhtml+xml", request);
+ response.setContentType(mimeType + "; charset=" + YanelServlet.DEFAULT_ENCODING);
+ response.setStatus(javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED);
+
+ File realmDir = realm.getRootDir();
+ if (realmDir == null) realmDir = new File(realm.getConfigFile().getParent());
+ File xsltLoginScreen = org.wyona.commons.io.FileUtil.file(realmDir.getAbsolutePath(), "src" + File.separator + "webapp" + File.separator + xsltLoginScreenDefault);
+ if (!xsltLoginScreen.isFile()) xsltLoginScreen = org.wyona.commons.io.FileUtil.file(servletContextRealPath, xsltLoginScreenDefault);
+
+ Transformer transformer = TransformerFactory.newInstance().newTransformer(new StreamSource(xsltLoginScreen));
+ transformer.setParameter("yanel.back2realm", backToRealm);
+ transformer.setParameter("yanel.reservedPrefix", reservedPrefix);
+ transformer.transform(new javax.xml.transform.dom.DOMSource(adoc), new javax.xml.transform.stream.StreamResult(response.getWriter()));
+ }
+
+
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ throw new ServletException(e.getMessage());
+ }
+ }
+
+ /**
+ * Patch request with proxy settings re realm configuration
+ */
+ private String getRequestURLQS(HttpServletRequest request, String addQS, boolean xml, Map map) {
+ try {
+ Realm realm = map.getRealm(request.getServletPath());
+
+ // TODO: Handle this exception more gracefully!
+ if (realm == null) log.error("No realm found for path " +request.getServletPath());
+
+ String proxyHostName = realm.getProxyHostName();
+ int proxyPort = realm.getProxyPort();
+ String proxyPrefix = realm.getProxyPrefix();
+
+ URL url = null;
+
+ url = new URL(request.getRequestURL().toString());
+
+ //if(proxyHostName != null || proxyPort >= null || proxyPrefix != null) {
+ if(realm.isProxySet()) {
+ if (proxyHostName != null) {
+ url = new URL(url.getProtocol(), proxyHostName, url.getPort(), url.getFile());
+ }
+
+ if (proxyPort >= 0) {
+ url = new URL(url.getProtocol(), url.getHost(), proxyPort, url.getFile());
+ } else {
+ url = new URL(url.getProtocol(), url.getHost(), url.getDefaultPort(), url.getFile());
+ }
+
+ if (proxyPrefix != null) {
+ url = new URL(url.getProtocol(), url.getHost(), url.getPort(), url.getFile().substring(proxyPrefix.length()));
+ }
+ //log.debug("Proxy enabled for this realm resp. request: " + realm + ", " + url);
+ } else {
+ //log.debug("No proxy set for this realm resp. request: " + realm + ", " + url);
+ }
+
+ String urlQS = url.toString();
+ if (request.getQueryString() != null) {
+ urlQS = urlQS + "?" + request.getQueryString();
+ if (addQS != null) urlQS = urlQS + "&" + addQS;
+ } else {
+ if (addQS != null) urlQS = urlQS + "?" + addQS;
+ }
+
+ if (xml) urlQS = urlQS.replaceAll("&", "&");
+
+ if(log.isDebugEnabled()) log.debug("Request: " + urlQS);
+
+ return urlQS;
+ } catch (Exception e) {
+ log.error(e);
+ return null;
+ }
+ }
+}
More information about the Yanel-commits
mailing list