changeset 9500:649e146c7d40

Merge
author gernotbelger
date Thu, 27 Sep 2018 18:08:17 +0200
parents 853f2dafc16e (current diff) 7b4b66c7b303 (diff)
children cb3dabb77857
files gwt-client/src/main/java/org/dive4elements/river/client/server/auth/saml/User.java
diffstat 11 files changed, 145 insertions(+), 229 deletions(-) [+]
line wrap: on
line diff
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/services/UserCollectionsService.java	Thu Sep 27 18:06:26 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/services/UserCollectionsService.java	Thu Sep 27 18:08:17 2018 +0200
@@ -11,6 +11,7 @@
 import com.google.gwt.user.client.rpc.RemoteService;
 import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
 
+import org.dive4elements.river.client.server.auth.User;
 import org.dive4elements.river.client.shared.model.Collection;
 
 
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/LoginServlet.java	Thu Sep 27 18:06:26 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/LoginServlet.java	Thu Sep 27 18:08:17 2018 +0200
@@ -10,16 +10,16 @@
 
 import java.io.IOException;
 
+import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
-import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import org.apache.log4j.Logger;
-
 import org.dive4elements.river.client.server.auth.Authentication;
 import org.dive4elements.river.client.server.auth.AuthenticationException;
 import org.dive4elements.river.client.server.auth.AuthenticationFactory;
+import org.dive4elements.river.client.server.auth.User;
 import org.dive4elements.river.client.server.features.Features;
 
 public class LoginServlet extends AuthenticationServlet {
@@ -27,12 +27,10 @@
     private static Logger log = Logger.getLogger(LoginServlet.class);
 
     @Override
-    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
-    throws ServletException, IOException
-    {
-        String encoding = req.getCharacterEncoding();
-        String username = req.getParameter("username");
-        String password = req.getParameter("password");
+    protected void doPost(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
+        final String encoding = req.getCharacterEncoding();
+        final String username = req.getParameter("username");
+        final String password = req.getParameter("password");
 
         log.debug("Processing post request");
 
@@ -43,33 +41,29 @@
         }
 
         try {
-            Authentication aresp = this.auth(username, password, encoding);
+            final Authentication aresp = this.auth(username, password, encoding);
             if (aresp == null || !aresp.isSuccess()) {
                 log.debug("Authentication not successful");
                 this.redirectFailure(resp, req.getContextPath());
                 return;
             }
-            log.info("Authentication successfull.");
-            this.performLogin(req, resp, aresp.getUser());
+
+            final User user = aresp.getUser();
+            final String userGroup = user.getUserGroup();
+
+            log.info(String.format("Authentication successfull: group = '%s'", userGroup));
+            this.performLogin(req, resp, user);
         }
-        catch(AuthenticationException e) {
+        catch (final AuthenticationException e) {
             log.error(e.getMessage());
             this.redirectFailure(resp, req.getContextPath(), e);
         }
     }
 
-    private Authentication auth(
-        String username,
-        String password,
-        String encoding
-    )
-        throws AuthenticationException, IOException
-    {
-        ServletContext sc = this.getServletContext();
-        Features features = (Features)sc.getAttribute(
-            Features.CONTEXT_ATTRIBUTE);
-        String auth = sc.getInitParameter("authentication");
-        return AuthenticationFactory.getInstance(auth).auth(username, password,
-                encoding, features, sc);
+    private Authentication auth(final String username, final String password, final String encoding) throws AuthenticationException, IOException {
+        final ServletContext sc = this.getServletContext();
+        final Features features = (Features) sc.getAttribute(Features.CONTEXT_ATTRIBUTE);
+        final String auth = sc.getInitParameter("authentication");
+        return AuthenticationFactory.getInstance(auth).auth(username, password, encoding, features, sc);
     }
-}
+}
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/SamlServlet.java	Thu Sep 27 18:06:26 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/SamlServlet.java	Thu Sep 27 18:08:17 2018 +0200
@@ -12,32 +12,28 @@
 import java.io.InputStream;
 import java.io.StringBufferInputStream;
 
+import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
-import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 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.saml.TicketValidator;
 import org.dive4elements.river.client.server.auth.saml.Assertion;
+import org.dive4elements.river.client.server.auth.saml.TicketValidator;
+import org.dive4elements.river.client.server.auth.was.Response;
 import org.dive4elements.river.client.server.features.Features;
 
-
 public class SamlServlet extends AuthenticationServlet {
 
     private static Logger log = Logger.getLogger(SamlServlet.class);
 
     @Override
-    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
-    throws ServletException, IOException
-    {
-        String encoding = req.getCharacterEncoding();
-        String samlTicketXML = req.getParameter("saml");
+    protected void doPost(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
+        // final String encoding = req.getCharacterEncoding();
+        final String samlTicketXML = req.getParameter("saml");
 
         log.debug("Processing post request");
 
@@ -48,7 +44,7 @@
         }
 
         try {
-            User user = this.auth(samlTicketXML);
+            final User user = this.auth(samlTicketXML);
             if (user == null) {
                 log.debug("Authentication not successful");
                 this.redirectFailure(resp, req.getContextPath());
@@ -57,40 +53,33 @@
             this.performLogin(req, resp, user);
             log.info("Authentication with existing SAML ticket.");
         }
-        catch(AuthenticationException e) {
+        catch (final AuthenticationException e) {
             log.error(e, e);
             this.redirectFailure(resp, req.getContextPath(), e);
         }
     }
 
-    private User auth(String samlTicketXML)
-        throws AuthenticationException, IOException
-    {
-        ServletContext sc = this.getServletContext();
+    private User auth(final String samlTicketXML) throws AuthenticationException {
+        final ServletContext sc = this.getServletContext();
 
         Assertion assertion = null;
         try {
-            String keyfile =
-                (String)sc.getInitParameter("saml-trusted-public-key");
-            int timeEps = Integer.parseInt(
-                sc.getInitParameter("saml-time-tolerance"));
-            TicketValidator validator =
-                new TicketValidator(sc.getRealPath(keyfile), timeEps);
+            final String keyfile = sc.getInitParameter("saml-trusted-public-key");
+            final int timeEps = Integer.parseInt(sc.getInitParameter("saml-time-tolerance"));
+            final TicketValidator validator = new TicketValidator(sc.getRealPath(keyfile), timeEps);
 
-            InputStream in = new StringBufferInputStream(samlTicketXML);
+            final InputStream in = new StringBufferInputStream(samlTicketXML);
             assertion = validator.checkTicket(new Base64InputStream(in));
         }
-        catch (Exception e) {
+        catch (final Exception e) {
             log.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, samlTicketXML,
-            features.getFeatures(assertion.getRoles()), null);
+        if (assertion == null)
+            throw new AuthenticationException("Login failed.");
+
+        final Features features = (Features) sc.getAttribute(Features.CONTEXT_ATTRIBUTE);
+
+        return Response.createUser(null, samlTicketXML, assertion, features);
     }
-}
+}
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/Authentication.java	Thu Sep 27 18:06:26 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/Authentication.java	Thu Sep 27 18:08:17 2018 +0200
@@ -12,12 +12,13 @@
  */
 public interface Authentication {
 
-    /** Returns true if the authentication was successfull
+    /**
+     * Returns true if the authentication was successfull
      */
-    public boolean isSuccess();
+    boolean isSuccess();
 
-    /** Returns a new User object
+    /**
+     * Returns a new User object
      */
-    public User getUser() throws AuthenticationException;
-
-}
+    User getUser() throws AuthenticationException;
+}
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/DefaultUser.java	Thu Sep 27 18:06:26 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/DefaultUser.java	Thu Sep 27 18:08:17 2018 +0200
@@ -10,62 +10,41 @@
 
 import java.util.List;
 
-public class DefaultUser
-implements   User
-{
-    protected String  name;
-    protected String  account;
-    protected String  password;
-    protected String  samlXML;
-    protected boolean expired;
-    protected List<String> roles;
-    protected List<String> features;
-
-    public DefaultUser() {
-    }
+public class DefaultUser implements User {
+    private final String name;
+    private final String account;
+    private final String password;
+    private final String samlXML;
+    private final boolean expired;
+    private final List<String> roles;
+    private final List<String> features;
+    private final String userGroup;
 
-    public DefaultUser(
-        String       name,
-        String       password,
-        String       samlXML,
-        boolean      expired,
-        List<String> roles,
-        List<String> features
-    ) {
-        this.name     = name;
+    public DefaultUser(final String name, final String password, final String samlXML, final boolean expired, final List<String> roles,
+            final List<String> features, final String userGroup) {
+        this.name = name;
         this.password = password;
-        this.samlXML  = samlXML;
-        this.expired  = expired;
-        this.roles    = roles;
+        this.samlXML = samlXML;
+        this.expired = expired;
+        this.roles = roles;
         this.features = features;
-        this.account  = name;
+        this.account = name;
+        this.userGroup = userGroup;
     }
 
     @Override
     public String getName() {
-        return name;
-    }
-
-    public void setName(String name) {
-        this.name = name;
+        return this.name;
     }
 
     @Override
     public String getPassword() {
-        return password;
-    }
-
-    public void setPassword(String password) {
-        this.password = password;
+        return this.password;
     }
 
     @Override
     public boolean hasExpired() {
-        return expired;
-    }
-
-    public void setExpired(boolean expired) {
-        this.expired = expired;
+        return this.expired;
     }
 
     @Override
@@ -74,35 +53,27 @@
         return this.roles;
     }
 
-    public void setRoles(List<String> roles) {
-        this.roles = roles;
+    public List<String> getAllowedFeatures() {
+        return this.features;
     }
 
     @Override
-    public boolean canUseFeature(String feature) {
+    public boolean canUseFeature(final String feature) {
         return this.features.contains(feature);
     }
 
-    public void setAllowedFeatures(List<String> features) {
-        this.features = features;
-    }
-
     @Override
     public String getAccount() {
         return this.account;
     }
 
-    public void setAccount(String account) {
-        this.account = account;
-    }
-
     @Override
     public String getSamlXMLBase64() {
         return this.samlXML;
     }
 
-    public void setSamlXMLBase64(String samlXML) {
-        this.samlXML = samlXML;
+    @Override
+    public String getUserGroup() {
+        return this.userGroup;
     }
-}
-// vim:set ts=4 sw=4 si et fenc=utf8 tw=80:
+}
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/User.java	Thu Sep 27 18:06:26 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/User.java	Thu Sep 27 18:08:17 2018 +0200
@@ -18,40 +18,41 @@
     /**
      * Returns the username as String
      */
-    public String getName();
+    String getName();
 
     /**
      * Returns the password of the user as String
      */
-    public String getPassword();
+    String getPassword();
 
     /**
      * Returns True if the authentication for the user
      * has expired.
      */
-    public boolean hasExpired();
+    boolean hasExpired();
 
     /**
      * Returns a list of roles corresponsing the the user
      */
-    public List<String> getRoles();
+    List<String> getRoles();
 
 
     /**
      * Returns true if the user is allowed access the feature
      */
-    public boolean canUseFeature(String feature);
+    boolean canUseFeature(String feature);
 
     /**
      * Returns the users account name
      */
-    public String getAccount();
+    String getAccount();
 
     /**
      * Returns the SAML ticket for single sign-on.
      * @return The SAML ticket in base64 encoded XML. null if no ticket
      * is available.
      */
-    public String getSamlXMLBase64();
-}
-// vim:set ts=4 sw=4 si et fenc=utf8 tw=80:
+    String getSamlXMLBase64();
+
+    String getUserGroup();
+}
\ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/plain/Authenticator.java	Thu Sep 27 18:06:26 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/plain/Authenticator.java	Thu Sep 27 18:08:17 2018 +0200
@@ -65,7 +65,7 @@
             return isSuccess()
                 ? new DefaultUser(
                     user, password, null, false, roles,
-                    this.features.getFeatures(roles))
+                    this.features.getFeatures(roles), null)
                 : null;
         }
     } // class Authentication
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/saml/User.java	Thu Sep 27 18:06:26 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/* 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.auth.saml;
-
-import java.util.List;
-
-import org.dive4elements.river.client.server.auth.DefaultUser;
-
-public class User
-extends DefaultUser
-implements org.dive4elements.river.client.server.auth.User {
-
-    private Assertion assertion;
-
-    public User(Assertion assertion, String samlXML, List<String> features,
-                String password) {
-        this.setName(assertion.getNameID());
-        this.setAccount(assertion.getNameID());
-        this.setRoles(assertion.getRoles());
-        this.assertion = assertion;
-        this.setSamlXMLBase64(samlXML);
-        this.setAllowedFeatures(features);
-        this.setPassword(password);
-    }
-
-    @Override
-    public boolean hasExpired() {
-        // We could check the validity dates of the assertion here, but
-        // when using this for Single-Sign-On this would lead to the
-        // code in GGInAFilter to re-authenticate with the password
-        // stored in the User object, which isn't known in the case of
-        // Single-Sign-On.
-        return false;
-    }
-}
-
-// vim:set ts=4 sw=4 si et fenc=utf8 tw=80:
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/was/Authenticator.java	Thu Sep 27 18:06:26 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/was/Authenticator.java	Thu Sep 27 18:08:17 2018 +0200
@@ -66,7 +66,7 @@
                     (String)context.getInitParameter("saml-trusted-public-key");
                     String timeEpsilon = context.getInitParameter(
                         "saml-time-tolerance");
-                    return new Response(entity, username, password, features,
+                    return new Response(entity, password, features,
                         context.getRealPath(trustedKey), timeEpsilon);
                 }
             }
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/was/Response.java	Thu Sep 27 18:06:26 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/was/Response.java	Thu Sep 27 18:08:17 2018 +0200
@@ -14,50 +14,42 @@
 import java.util.List;
 
 import org.apache.commons.codec.binary.Base64InputStream;
-
 import org.apache.http.HttpEntity;
 import org.apache.http.util.EntityUtils;
-
 import org.apache.log4j.Logger;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
 import org.dive4elements.artifacts.httpclient.utils.XMLUtils;
 import org.dive4elements.river.client.server.auth.Authentication;
 import org.dive4elements.river.client.server.auth.AuthenticationException;
+import org.dive4elements.river.client.server.auth.DefaultUser;
+import org.dive4elements.river.client.server.auth.User;
 import org.dive4elements.river.client.server.auth.saml.Assertion;
-import org.dive4elements.river.client.server.auth.saml.XPathUtils;
 import org.dive4elements.river.client.server.auth.saml.TicketValidator;
-import org.dive4elements.river.client.server.auth.saml.User;
-
+import org.dive4elements.river.client.server.auth.saml.XPathUtils;
 import org.dive4elements.river.client.server.features.Features;
-
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
 
 public class Response implements Authentication {
 
     private static Logger log = Logger.getLogger(Response.class);
 
-    private Element root;
-    private String samlTicketXML;
+    private final Element root;
+    private final String samlTicketXML;
     private Assertion assertion;
-    private String username;
-    private String password;
-    private Features features;
-    private String trustedKeyFile;
-    private String timeEpsilon;
+    private final String password;
+    private final Features features;
+    private final String trustedKeyFile;
+    private final String timeEpsilon;
 
-
-    public Response(HttpEntity entity, String username, String password,
-            Features features, String trustedKeyFile, String timeEpsilon)
-        throws AuthenticationException, IOException {
+    public Response(final HttpEntity entity, final String password, final Features features, final String trustedKeyFile,
+            final String timeEpsilon) throws AuthenticationException, IOException {
 
         if (entity == null) {
             throw new ServiceException("Invalid response");
         }
 
-        String contenttype = entity.getContentType().getValue();
-        String samlTicketXML = EntityUtils.toString(entity);
+        final String contenttype = entity.getContentType().getValue();
+        final String samlTicketXML = EntityUtils.toString(entity);
 
         InputStream in = new StringBufferInputStream(samlTicketXML);
 
@@ -66,18 +58,15 @@
             in = new Base64InputStream(in);
         }
 
-        Document doc = XMLUtils.readDocument(in);
-        Element root = doc.getDocumentElement();
-        String rname = root.getTagName();
+        final Document doc = XMLUtils.readDocument(in);
+        final Element root = doc.getDocumentElement();
+        final String rname = root.getTagName();
 
-        if (rname != null && rname.equals("ServiceExceptionReport")) {
-            throw new ServiceException(XPathUtils.xpathString(root,
-                                                          "ServiceException"));
-        }
+        if (rname != null && rname.equals("ServiceExceptionReport"))
+            throw new ServiceException(XPathUtils.xpathString(root, "ServiceException"));
 
         this.samlTicketXML = samlTicketXML;
         this.root = root;
-        this.username = username;
         this.password = password;
         this.features = features;
         this.trustedKeyFile = trustedKeyFile;
@@ -86,25 +75,22 @@
 
     @Override
     public boolean isSuccess() {
-        String status = getStatus();
+        final String status = getStatus();
         return status != null && status.equals("samlp:Success");
     }
 
-    public String getStatus() {
-        return XPathUtils.xpathString(this.root,
-            "./samlp:Status/samlp:StatusCode/@Value");
+    private String getStatus() {
+        return XPathUtils.xpathString(this.root, "./samlp:Status/samlp:StatusCode/@Value");
     }
 
-
-    public Assertion getAssertion() {
+    private Assertion getAssertion() {
         if (this.assertion == null && this.root != null) {
             try {
-                int timeEps = Integer.parseInt(this.timeEpsilon);
-                TicketValidator validator =
-                    new TicketValidator(this.trustedKeyFile, timeEps);
+                final int timeEps = Integer.parseInt(this.timeEpsilon);
+                final TicketValidator validator = new TicketValidator(this.trustedKeyFile, timeEps);
                 this.assertion = validator.checkTicket(this.root);
             }
-            catch (Exception e) {
+            catch (final Exception e) {
                 log.error(e.getLocalizedMessage(), e);
             }
         }
@@ -113,16 +99,32 @@
 
     @Override
     public User getUser() throws AuthenticationException {
-        Assertion assertion = this.getAssertion();
-        if (assertion == null) {
-            throw new AuthenticationException(
-                "Response doesn't contain an assertion");
-        }
-        List<String> features = this.features.getFeatures(
-                this.assertion.getRoles());
-        log.debug("User " + this.username + " with features " + features +
-                     " successfully authenticated.");
-        return new User(assertion, this.samlTicketXML, features, this.password);
+        final Assertion assertion = this.getAssertion();
+        if (assertion == null)
+            throw new AuthenticationException("Response doesn't contain an assertion");
+
+        final DefaultUser user = createUser(this.password, this.samlTicketXML, assertion, this.features);
+
+        log.debug("User " + user.getName() + " with features " + user.getAllowedFeatures() + " successfully authenticated.");
+
+        return user;
     }
-}
-// vim: set si et fileencoding=utf-8 ts=4 sw=4 tw=80:
+
+    public static DefaultUser createUser(final String password, final String samlTicketXML, final Assertion assertion, final Features features) {
+        final List<String> roles = assertion.getRoles();
+
+        final List<String> allowedFeatures = features.getFeatures(roles);
+
+        // We could check the validity dates of the assertion here, but
+        // when using this for Single-Sign-On this would lead to the
+        // code in GGInAFilter to re-authenticate with the password
+        // stored in the User object, which isn't known in the case of
+        // Single-Sign-On.
+        final boolean expired = false;
+
+        final String username = assertion.getNameID();
+        final String userGroup = assertion.getGroupName();
+
+        return new DefaultUser(username, password, samlTicketXML, expired, roles, allowedFeatures, userGroup);
+    }
+}
\ No newline at end of file
--- a/gwt-client/src/test/java/test/AbstractModuleRunner.java	Thu Sep 27 18:06:26 2018 +0200
+++ b/gwt-client/src/test/java/test/AbstractModuleRunner.java	Thu Sep 27 18:08:17 2018 +0200
@@ -111,7 +111,7 @@
     }
 
     private static String makeUserUuid(final String serverUrl) throws ConnectionException {
-        final User user = new DefaultUser(USERNAME, PASSWORD, null, false, new ArrayList<String>(), new ArrayList<String>());
+        final User user = new DefaultUser(USERNAME, PASSWORD, null, false, new ArrayList<String>(), new ArrayList<String>(), null);
         final UserClient userClient = new UserClient(serverUrl);
         Element userElement;
 

http://dive4elements.wald.intevation.org