# HG changeset patch # User Bernhard Herzog # Date 1368028574 -7200 # Node ID 38d161edba77fe1e8c4c41821dc2efc054ce4fc5 # Parent 0a0b4bfdf3721d036487989c008440a924171abf Add SamlServlet to implement actual login via SAML Ticket. This is the main part of single-sign-on for flys from issue1265. SamlServlet is an adapted copy of LoginServlet. The code shared by both classes will be extracted into a base class later. diff -r 0a0b4bfdf372 -r 38d161edba77 gwt-client/src/main/java/org/dive4elements/river/client/server/SamlServlet.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/SamlServlet.java Wed May 08 17:56:14 2013 +0200 @@ -0,0 +1,148 @@ +/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde + * Software engineering by Intevation GmbH + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ + +package org.dive4elements.river.client.server; + +import java.io.IOException; +import java.io.InputStream; +import java.io.StringBufferInputStream; + +import javax.servlet.ServletException; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.commons.codec.binary.Base64InputStream; + +import org.apache.log4j.Logger; + +import org.dive4elements.river.client.server.auth.AuthenticationException; +import org.dive4elements.river.client.server.auth.User; +import org.dive4elements.river.client.server.auth.UserClient; +import org.dive4elements.river.client.server.auth.saml.TicketValidator; +import org.dive4elements.river.client.server.auth.saml.Assertion; +import org.dive4elements.river.client.server.features.Features; + + +public class SamlServlet extends HttpServlet { + + private static Logger logger = Logger.getLogger(SamlServlet.class); + + private static final String FLYS_PAGE = "FLYS.html"; + private static final String LOGIN_PAGE = "login.jsp"; + + private void redirectFailure(HttpServletResponse resp, String path) + throws IOException { + resp.sendRedirect(path + "/" + LOGIN_PAGE); + } + + private void redirectFailure(HttpServletResponse resp, String path, + Exception e) throws IOException { + this.redirectFailure(resp, path, e.getMessage()); + } + + private void redirectFailure(HttpServletResponse resp, String path, + String message) throws IOException { + resp.sendRedirect(path + "/" + LOGIN_PAGE + "?error=" + message); + } + + private void redirectSuccess(HttpServletResponse resp, String path, + String uri) throws IOException { + if (uri == null) { + String redirecturl = getServletContext().getInitParameter("redirect-url"); + if (redirecturl == null) { + redirecturl = FLYS_PAGE; + } + uri = "/" + redirecturl; + } + resp.sendRedirect(uri); + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + logger.debug("Processing get request"); + this.redirectFailure(resp, req.getContextPath()); + } + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException + { + String encoding = req.getCharacterEncoding(); + String samlTicketXML = req.getParameter("samlTicket"); + + logger.debug("Processing post request"); + + if (samlTicketXML == null) { + logger.debug("No saml ticket provided"); + this.redirectFailure(resp, req.getContextPath()); + return; + } + + try { + User user = this.auth(samlTicketXML); + if (user == null) { + logger.debug("Authentication not successful"); + this.redirectFailure(resp, req.getContextPath()); + return; + } + + String url = getServletContext().getInitParameter("server-url"); + UserClient client = new UserClient(url); + if (!client.userExists(user)) { + logger.debug("Creating db user"); + if (!client.createUser(user)) { + this.redirectFailure(resp, req.getContextPath(), + "Could not create new user"); + return; + } + } + + HttpSession session = req.getSession(); + session.setAttribute("user", user); + + String uri = (String)session.getAttribute("requesturi"); + + this.redirectSuccess(resp, req.getContextPath(), uri); + } + catch(AuthenticationException e) { + logger.error(e, e); + this.redirectFailure(resp, req.getContextPath(), e); + } + } + + private User auth(String samlTicketXML) + throws AuthenticationException, IOException + { + ServletContext sc = this.getServletContext(); + + Assertion assertion = null; + try { + String keyfile = + (String)sc.getInitParameter("saml-trusted-public-key"); + TicketValidator validator = + new TicketValidator(sc.getRealPath(keyfile)); + + InputStream in = new StringBufferInputStream(samlTicketXML); + assertion = validator.checkTicket(new Base64InputStream(in)); + } + catch (Exception e) { + logger.error(e.getLocalizedMessage(), e); + } + if (assertion == null) { + throw new AuthenticationException("Login failed."); + } + + Features features = (Features)sc.getAttribute(Features.CONTEXT_ATTRIBUTE); + return new org.dive4elements.river.client.server.auth.saml.User( + assertion, features.getFeatures(assertion.getRoles()), null); + } +}