[Yanel-dev] Auto Login

basZero baszero at gmail.com
Tue Jul 5 16:21:16 CEST 2011


I think you did not apply the latest patch? on line 130 there can't be a
NullPointer...
Here it is a fresh one.

Let me know whether it works.
Cheers
Balz

On Tue, Jul 5, 2011 at 4:14 PM, Michael Wechner
<michael.wechner at wyona.com>wrote:

> **
> Hi Balz
>
> I have applied your latest patch re auto login which you have sent to me
> offlist), but receive the following error:
>
> 71951 2011-07-05 16:11:53,785 +0200 [http-8080-Processor22] WARN
> org.wyona.yanel.servlet.YanelServlet.doAccessControl():1122  - Access
> denied:
> http://127.0.0.1:8080/yanel/from-scratch-realm/en/index.html?yanel.toolbar=on(Path of request: /en/index.html; Identity: User ID: WORLD - Groups: ;
> Usecase: toolbar)
> 71951 2011-07-05 16:11:53,785 +0200 [http-8080-Processor22] WARN
> org.wyona.yanel.servlet.YanelServlet.doAccessControl():1152  - SSL does not
> seem to be configured!
> 71981 2011-07-05 16:11:53,815 +0200 [http-8080-Processor22] WARN
> org.wyona.security.impl.yarep.YarepUserManager.getTrueId():503  - No alias
> found for id 'lenya', hence return id as true ID
> 72028 2011-07-05 16:11:53,862 +0200 [http-8080-Processor22] WARN
> org.wyona.yanel.servlet.security.impl.DefaultWebAuthenticatorImpl.authenticate():680
> - Authentication was successful for user: lenya
> 72030 2011-07-05 16:11:53,864 +0200 [http-8080-Processor22] WARN
> org.wyona.yanel.servlet.security.impl.DefaultWebAuthenticatorImpl.authenticate():681
> - TODO: Add user to session listener!
> 72030 2011-07-05 16:11:53,864 +0200 [http-8080-Processor22] WARN
> org.wyona.yanel.servlet.security.impl.DefaultWebAuthenticatorImpl.doAutoLogin():610
> - TODO: Implement auto-login
> 72031 2011-07-05 16:11:53,865 +0200 [http-8080-Processor22] FATAL
> org.wyona.yanel.servlet.security.impl.AutoLogin.enableAutoLogin():66  -
> Could not enable Auto Login feature! Exception:
> java.lang.NullPointerException
> java.lang.NullPointerException
>     at
> org.wyona.yanel.servlet.security.impl.AutoLogin.setNewCookie(AutoLogin.java:130)
>     at
> org.wyona.yanel.servlet.security.impl.AutoLogin.enableAutoLogin(AutoLogin.java:62)
>     at
> org.wyona.yanel.servlet.security.impl.DefaultWebAuthenticatorImpl.doAutoLogin(DefaultWebAuthenticatorImpl.java:613)
>     at
> org.wyona.yanel.servlet.security.impl.DefaultWebAuthenticatorImpl.doAuthenticate(DefaultWebAuthenticatorImpl.java:106)
>     at
> org.wyona.yanel.servlet.YanelServlet.doAuthenticate(YanelServlet.java:1393)
>     at
> org.wyona.yanel.servlet.YanelServlet.doAccessControl(YanelServlet.java:1158)
>     at org.wyona.yanel.servlet.YanelServlet.service(YanelServlet.java:253)
>     at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
>     at
> org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
>     at
> org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
>     at
> org.wyona.yanel.servlet.communication.YanelFilter.doFilter(YanelFilter.java:37)
>     at
> org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
>     at
> org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
>     at
> org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
>     at
> org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
>     at
> org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
>     at
> org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
>     at
> org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
>     at
> org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
>     at
> org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)
>     at
> org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:664)
>     at
> org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
>     at
> org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
>     at
> org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
>     at java.lang.Thread.run(Thread.java:680)
> 72032 2011-07-05 16:11:53,866 +0200 [http-8080-Processor22] WARN
> org.wyona.yanel.servlet.YanelServlet.doAccessControl():1178  -
> Authentication was successful for user: lenya
> 72032 2011-07-05 16:11:53,866 +0200 [http-8080-Processor22] WARN
> org.wyona.yanel.servlet.YanelServlet.doAccessControl():1187  - Redirect to
> original request:
> http://127.0.0.1:8080/yanel/from-scratch-realm/en/index.html?yanel.toolbar=on
>
> Can you send me another version or maybe we can have a look at it together
> tomorrow morning?
>
> WDYT?
>
> Thanks
>
> Michael
>
> Am 17.05.11 16:15, schrieb basZero:
>
> Hi Michael,
>
>  can you verify this patch for the AutoLogin class?
> If it is ok, you can submit it.
> How do we proceed?
>
>  I have implemented the AutoLogin call after successful login, so the rest
> must be done in the YanelServlet and the Authenticator.
>
>  Cheers
> Balz
>
> On Tue, May 17, 2011 at 11:34 AM, Michael Wechner <
> michael.wechner at wyona.com> wrote:
>
>>  Hi Balz
>>
>> As we have discussed offline I have now added the relevant calls and
>> utility class:
>>
>> src/webapp/src/java/org/wyona/yanel/servlet/security/impl/AutoLogin.java
>>
>>
>> src/webapp/src/java/org/wyona/yanel/servlet/security/impl/DefaultWebAuthenticatorImpl.java
>>  src/webapp/src/java/org/wyona/yanel/servlet/YanelServlet.java
>>
>> whereas just as the class DefaultWebAuthenticatorImpl is using the utility
>> class AutoLogin,
>> you can use this utility class within your custom code and as long as you
>> don't pass the form parameter "auto-login" (e.g. used by
>> src/webapp/xslt/login-screen.xsl) the DefaultWebAuthenticatorImpl will
>> ignore it.
>>
>> The code does not do much yet and the AutoLogin class methods needs to be
>> refined (in particular the setCookie(...) method), but maybe you can test if
>> this integrates well with your custom code and if so,
>> then I think it should be generic enough and easy integratable.
>>
>> Let me know and the we can start the actual implementation.
>>
>> Thanks
>>
>> Michael
>>
>>
>> On 5/17/11 8:15 AM, basZero wrote:
>>
>> Hi Michael,
>> I think it is not a good idea to store the token in the user profile. Read
>> my consolidated thoughts about the auto-login:
>>
>>  - In order
>> to give a realm flexibility on HOW the autologin gets
>> implemented, I would suggest that you can configure (per
>> realm) an AutoLoginService (e.g. in the realms.xml) which
>> gets called by the YanelServlet. This way you don't have to
>> worry about all the details now (what to store where and
>> how, etc.) because these are then up to the realm's
>> implementation (if it wants to use Auto-Login).
>>
>> - Given this design you can later introduce a
>> DefaultAutoLoginServiceImpl class which a realm can use if
>> they are happy with how that implementation does handle the
>> autologin.
>>
>> - The AutoLoginService gets called by the YanelServlet for EACH request that is NOT BOUND to any session yet (so that equals to the first request per session).
>> - So the AutoLoginServive would get the Yanel Environment object (via that it has access to request, response, session, etc., --> the session must be created before the AutoLoginService gets called, it might want to store values in it).
>> - In general I think we need to extend the DefaultAuthenticatorImpl in Yanel so that you can "login" the user by just providing the username.
>>
>> My points regarding the AutoLoginService:
>>
>> - Define NEW COOKIE (e.g. YANEL_AUTOLOGIN, it contains userID and a TOKEN)
>> - Verify that the user is really not logged in yet. If logged in --> return.
>> - The TOKEN must be found VERY QUICKLY, we can not go through 10'000 user profiles and look for the token --> Either store it as a seperate XML (data/autologin/<tokenid>.xml , or we save in a separate index (at Zwischengas we use an internal index for that already, separated from the actual content data)
>> - In the TOKEN DATA file (retrieved from token XML or Index), we get the userid for this token. It must match the userid provided from the COOKIE.
>> - If it matches and the token has not yet expired, we do the login for this user WITHOUT password.
>>
>> I currently wonder whether we really have to renew the TOKEN in the Autologin-Cookie, we could also keep it (like the Yanel-Cookie). What do you think?
>>
>> Cheers
>> Balz
>>
>>
>> On Tue, May 17, 2011 at 7:31 AM, <baszero at gmail.com> wrote:
>>
>>>  hi michael
>>>
>>>  i would rather store it in the user profile xml and not in the meta
>>> property.
>>>
>>>  cheers
>>>
>>>
>>>  _____________________
>>> CTO / Zwischengas AG
>>> www.zwischengas.com
>>>
>>>  Sent via iPhone
>>>
>>> On 16.05.2011, at 23:04, Michael Wechner <michael.wechner at wyona.com>
>>> wrote:
>>>
>>>   Hi Balz
>>>
>>> On 5/16/11 5:06 PM, basZero wrote:
>>>
>>> Hi Michael,
>>>
>>>  as just discussed, what I meant by "auto-login" is not just pre-filling
>>> the username field in the login form.
>>>
>>>
>>> sorry, right, I misunderstood
>>>
>>> By "auto-login", I mean the following:
>>>
>>>  - the user accesses ANY page within my realm
>>> - at every request it is verified whether the user is logged in (means:
>>> getIdentity() != null ?)
>>> - if there is no identity available, the request is checked for the
>>> autologin cookie
>>> - if there is no autologin cookie, proceed as usual (= user remains
>>> anonymous)
>>> - if there IS an autologin cookie, the user gets authenticated
>>> automatically (without seeing any form or the need of pressing a submit
>>> button) and the user is logged in.
>>>
>>>
>>> sounds good also from a peformance/scalability point of view, except it's
>>> unclear to me where
>>> we should save the tokens persistently and how to clean them if they have
>>> expired.
>>>
>>> I guess we could save them together with the user profile, e.g.
>>>
>>> getRealm().getIdentityManager().getUserManager().getUser("baszero").setProperty("autologin-token",
>>> TOKEN-ID);
>>>
>>> WDYT?
>>>
>>> Thanks
>>>
>>> Michael
>>>
>>>
>>>  *Implementation:*
>>> The standard way of how this usually gets implemented is as follows:
>>> - The cookie contains USERID, TOKEN
>>> - After every successful authentication, a new TOKEN gets created and
>>> stored in the COOKIE (for the next time). The realm also stores the new
>>> token for this user (so that it can be verified the next time).
>>> - How to do the authentication: the token from the cookie must match the
>>> last stored token for this user. if it matches, the user gets logged in
>>> without the need of the password.
>>>
>>>  A normal side effect of this implementation is:
>>> - if the user uses a web browser and for instance an iPad, every time he
>>> switches the device, the token obviously does not match anymore and he has
>>> to login by the usual login form where he enters username and password (and
>>> where he can checkbox the autologin feature again).
>>>
>>>  *Next steps for Yanel:*
>>> It would be great if this functionality could be plugged into the request
>>> pipeline of Yanel.
>>> An alternative is to write a Request Pipeline Filter for TOMCAT so that
>>> the request goes through that servlet each time.
>>>
>>>  What do you propose?
>>>
>>>  Cheers
>>> Balz
>>>
>>>
>>> On Mon, May 16, 2011 at 4:48 PM, Michael Wechner <
>>> michael.wechner at wyona.com> wrote:
>>>
>>>> Hi Balz
>>>>
>>>>
>>>> On 5/16/11 4:09 PM, basZero wrote:
>>>>
>>>>> Hi Michael,
>>>>>
>>>>> you once mentioned that Yanel comes out of the box with an auto login
>>>>> feature?
>>>>> Can you point me to the source code? I didn't find it.
>>>>>
>>>>
>>>>  Have a look at
>>>>
>>>>
>>>> src/webapp/src/java/org/wyona/yanel/servlet/security/impl/DefaultWebAuthenticatorImpl.java
>>>>
>>>> and search for
>>>>
>>>> remember-my-login-name
>>>>
>>>> (also see rememberLoginNameCookie.setMaxAge(86400); // 1 day is 86400
>>>> seconds)
>>>>
>>>> (also see src/webapp/xslt/login-screen.xsl)
>>>>
>>>> HTH
>>>>
>>>> Michael
>>>>
>>>>
>>>>> I just want to see how it is done.
>>>>>
>>>>> Cheers
>>>>> Balz
>>>>>
>>>>
>>>>   --
>>>> Yanel-development mailing list Yanel-development at wyona.com
>>>> http://lists.wyona.org/cgi-bin/mailman/listinfo/yanel-development
>>>>
>>>
>>>
>>>   --
>>> Yanel-development mailing list Yanel-development at wyona.com
>>> http://lists.wyona.org/cgi-bin/mailman/listinfo/yanel-development
>>>
>>>
>>
>>
>> --
>> Yanel-development mailing list Yanel-development at wyona.com
>> http://lists.wyona.org/cgi-bin/mailman/listinfo/yanel-development
>>
>
>
>
> --
> Yanel-development mailing list Yanel-development at wyona.com
> http://lists.wyona.org/cgi-bin/mailman/listinfo/yanel-development
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.wyona.org/pipermail/yanel-development/attachments/20110705/bf709129/attachment-0001.html>
-------------- next part --------------
Index: src/webapp/src/java/org/wyona/yanel/servlet/security/impl/AutoLogin.java
===================================================================
--- src/webapp/src/java/org/wyona/yanel/servlet/security/impl/AutoLogin.java	(revision 59190)
+++ src/webapp/src/java/org/wyona/yanel/servlet/security/impl/AutoLogin.java	(working copy)
@@ -1,5 +1,8 @@
 package org.wyona.yanel.servlet.security.impl;
 
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
 import java.util.UUID;
 
 import javax.servlet.http.Cookie;
@@ -7,25 +10,126 @@
 import javax.servlet.http.HttpServletResponse;
 
 import org.apache.log4j.Logger;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.wyona.commons.xml.XMLHelper;
+import org.wyona.yanel.core.Environment;
+import org.wyona.yanel.core.map.Realm;
+import org.wyona.yanel.core.util.YarepUtil;
+import org.wyona.yarep.core.Node;
+import org.wyona.yarep.core.Repository;
 
 /**
  * Utility class in order to support auto login
  */
 public class AutoLogin {
-
+    
     private static Logger log = Logger.getLogger(AutoLogin.class);
     private static final String COOKIE_NAME = "YANELAUTOLOGIN";
     private static final String SEP = "___";
+    
+    private static final String NAMESPACE = "http://www.wyona.org/yanel/1.0";
+    private static final String BASEDIR = "/autologin-tokens/";
+    private static final String EXPIRES_FORMAT = "yyyyMMdd.HH.mm.ss";
+    private static final SimpleDateFormat expiresSdf = new SimpleDateFormat(EXPIRES_FORMAT);
+    private static final String XML_ATTR_USERNAME = "username";
+    private static final String XML_ATTR_EXPIRES = "expires";
+    private static final String XML_ATTR_TOKEN = "token";
+    
+    // With the following two parameters you can define after what time a token gets replaced.
+    // However: this expiry date is only verified and maybe replaced if the user starts a new session.
+    // Means: if the session timeout is 4h and you configure here 30min, the cookie token won't be replaced within the session.
+    private static final int TOKEN_EXPIRY_UNIT = Calendar.MINUTE;
+    private static final int TOKEN_EXPIRY_AMOUNT = 30;
 
     /**
-     * Set cookie
+     * Disable Auto Login feature (deletes cookie)
      */
-    public static Cookie setCookie(String username, HttpServletRequest request, HttpServletResponse response) {
+    public static void disableAutoLogin(HttpServletRequest request, HttpServletResponse response, Repository repo) {
+        Cookie cookie = new Cookie(COOKIE_NAME,"");
+        cookie.setMaxAge(0);
+        response.addCookie(cookie);
+        cookie = getCookie(request);
+        deleteToken(repo, getYarepPath(getUsername(cookie), getToken(cookie)));
+    }
+    
+    public static void enableAutoLogin(String username, Environment environment, Realm realm) {
+        try {
+            //set cookie
+            Cookie cookie = setNewCookie(username, environment.getResponse());
+            //save token
+            saveToken(cookie, realm.getRepository());
+        } catch (Exception e) {
+            log.fatal("Could not enable Auto Login feature! Exception: "+e,e);
+        }
+    }
+    
+    public static String getUsername(HttpServletRequest request) {
+        return getUsername(getCookie(request));
+    }
+    
+    /**
+     * This method verifies whether the current user should get logged in automatically based on the cookie information and the persisted token
+     * @param request
+     * @param response
+     * @param realm
+     * @return true means that this user can be logged in automatically.
+     */
+    public static boolean doAutoLogin(HttpServletRequest request, HttpServletResponse response, Realm realm) {
+        boolean result = false;
+        try {
+            Cookie cookie = getCookie(request);
+            if (cookie != null) {
+                log.debug("Checking Autologin Cookie");
+                String username = getUsername(cookie);
+                String token = getToken(cookie);
+                if (username != null && token != null) {
+                    String yarepPath = getYarepPath(username, token);
+                    log.debug("Checking node "+yarepPath);
+                    Node node = null;
+                    try {
+                        node = realm.getRepository().getNode(yarepPath);
+                    } catch (Exception e) {
+                        log.debug("node '"+yarepPath+"' does not exist");
+                    }
+                    if (node != null) {
+                        Document doc = XMLHelper.readDocument(node.getInputStream());
+                        Element el = (Element)doc.getElementsByTagNameNS(NAMESPACE, XML_ATTR_TOKEN).item(0);
+                        String savedUsername = el.getAttribute(XML_ATTR_USERNAME);
+                        String savedToken = el.getAttribute("value");
+                        String expiryString = el.getAttribute(XML_ATTR_EXPIRES);
+                        log.debug("Retrieved username '"+username+"' and token '"+savedToken+"' from saved Token");
+                        if (username.equals(savedUsername) && token.equals(savedToken)) {
+                            result = true;
+                            log.debug("retrieved cookie matches for user '"+username+"'");
+                            if (hasTokenExpired(expiryString)) {
+                                Cookie newCookie = setNewCookie(username, response);
+                                saveToken(newCookie, realm.getRepository());
+                                deleteToken(realm.getRepository(), yarepPath);
+                                log.debug("Token was expired and has been renewed now.");
+                            }
+                        }
+                    }
+                }
+            }
+            
+        } catch (Exception e) {
+            log.error("Can not find out whether to perform auto login or not! Exception : "+e,e);
+        }
+        
+        return result;
+    }
+
+    /**
+     * Set cookie in response
+     */
+    private static Cookie setNewCookie(String username, HttpServletResponse response) {
         Cookie result = null;
         if (username != null) {
             String token = UUID.randomUUID().toString();
             Cookie cookie = new Cookie(COOKIE_NAME,token+SEP+username);
             cookie.setMaxAge(Integer.MAX_VALUE);
+            cookie.setPath("/");
             response.addCookie(cookie);
             result = cookie;
         }
@@ -35,20 +139,19 @@
     /**
      * Get cookie
      */
-    public static Cookie getCookie(HttpServletRequest request) {
+    private static Cookie getCookie(HttpServletRequest request) {
         Cookie result = null;
         try {
             Cookie[] cookies = request.getCookies();
             if (cookies != null) {
-                for (Cookie c : cookies) {
+                for (Cookie c : request.getCookies()) {
                     if (c.getName().equals(COOKIE_NAME)) {
                         result = c;
                         break;
                     }
                 }
-            } else {
-                log.warn("DEBUG: No cookies by browser provided yet!");
             }
+            
         } catch (Exception e) {
             log.error("Error in retrieving cookie from request");
             log.error(e,e);
@@ -57,18 +160,9 @@
         return result;
     }
     
-    public static String getUsername(HttpServletRequest request) {
+    private static String getUsername(Cookie cookie) {
         String result = null;
-        Cookie cookie = getCookie(request);
         if (cookie != null) {
-            result = getUsername(cookie);
-        }
-        return result;
-    }
-
-    public static String getUsername(Cookie cookie) {
-        String result = null;
-        if (cookie != null) {
             try {
                 result = cookie.getValue();
                 result = result.substring(result.lastIndexOf(SEP)+SEP.length());
@@ -80,18 +174,9 @@
         return result;
     }
 
-    public static String getToken(HttpServletRequest request) {
+    private static String getToken(Cookie cookie) {
         String result = null;
-        Cookie cookie = getCookie(request);
         if (cookie != null) {
-            result = getToken(cookie);
-        }
-        return result;
-    }
-
-    public static String getToken(Cookie cookie) {
-        String result = null;
-        if (cookie != null) {
             try {
                 result = cookie.getValue();
                 result = result.substring(0, result.lastIndexOf(SEP));
@@ -104,26 +189,75 @@
     }
 
     /**
-     * Remove cookie
+     * Save auto login token persistently
      */
-    public static void removeCookie(HttpServletRequest request, HttpServletResponse response) {
-        Cookie cookie = new Cookie(COOKIE_NAME,"");
-        cookie.setMaxAge(0);
-        response.addCookie(cookie);
+    private static void saveToken(Cookie cookie, Repository repo) {
+        String username = getUsername(cookie);
+        String token = getToken(cookie);
+        if (username != null && token != null) {
+            String yarepPath = getYarepPath(username, token);
+            Document doc = XMLHelper.createDocument(NAMESPACE, "root");
+            Element el = doc.createElementNS(NAMESPACE, XML_ATTR_TOKEN);
+            el.setAttribute("value", token);
+            el.setAttribute(XML_ATTR_USERNAME, username);
+            el.setAttribute(XML_ATTR_EXPIRES, getExpiryString());
+            doc.getDocumentElement().appendChild(el);
+            
+            // try to delete node if it exists
+            deleteToken(repo, yarepPath);
+            
+            // save the token
+            try {
+                Node node = YarepUtil.addNodes(repo, yarepPath, org.wyona.yarep.core.NodeType.RESOURCE);
+                XMLHelper.writeDocument(doc, node.getOutputStream());
+                log.debug("Autologin Token saved at "+yarepPath);
+            } catch (Exception e) {
+                log.error("Could not save token for Auto-Login. Exception: "+e,e);
+            }
+        }
     }
+    
+    private static String getExpiryString() {
+        String result = null;
+        try {
+            Calendar cal = Calendar.getInstance();
+            cal.add(TOKEN_EXPIRY_UNIT, TOKEN_EXPIRY_AMOUNT);
+            result = expiresSdf.format(cal.getTime());
+            
+        } catch (Exception e) {
+            log.error("Can not calculate expiry date! Exception: "+e,e);
+        }
+        return result;
+    }
+    
+    private static boolean hasTokenExpired(String expiryString) {
+        boolean result = true;
+        try {
+            if (expiryString != null) {
+                Date expiryDate = expiresSdf.parse(expiryString);
+                if (expiryDate.before(new Date())) {
+                    result = true;
+                } else {
+                    result = false;
+                }
+            }
+        } catch (Exception e) {
+            log.error("Can not parse the expirydate '"+expiryString+"' from the token XML! Exception: "+e,e);
+        }
+        return result;
+    }
 
-    /**
-     * Save auto login token persistently
-     */
-    public static void saveToken(Cookie cookie, org.wyona.yarep.core.Repository repo) {
-        // TODO
+    private static void deleteToken(Repository repo, String yarepPath) {
+        try {
+            if (repo.existsNode(yarepPath)) {
+                repo.getNode(yarepPath).delete();
+            }
+        } catch (Exception e) {
+            // we could log an exception here but deletion is not that important, so we skip the logging.
+        }
     }
 
-    /**
-     * Check whether cookie and token match
-     */
-    public static boolean matchCookie(Cookie cookie, org.wyona.yarep.core.Repository repo) {
-        // TODO
-        return false;
+    private static String getYarepPath(String username, String tokenID) {
+        return BASEDIR+username+"-tokens/"+tokenID+".xml";
     }
 }
Index: src/webapp/src/java/org/wyona/yanel/servlet/YanelServlet.java
===================================================================
--- src/webapp/src/java/org/wyona/yanel/servlet/YanelServlet.java	(revision 59190)
+++ src/webapp/src/java/org/wyona/yanel/servlet/YanelServlet.java	(working copy)
@@ -30,7 +30,6 @@
 
 import org.wyona.commons.xml.XMLHelper;
 
-import org.wyona.neutron.XMLExceptionV1;
 
 import org.wyona.yanel.core.ResourceTypeIdentifier;
 import org.wyona.yanel.core.StateOfView;
@@ -54,7 +53,6 @@
 import org.wyona.yanel.core.attributes.versionable.RevisionInformation;
 import org.wyona.yanel.core.attributes.viewable.View;
 import org.wyona.yanel.core.attributes.viewable.ViewDescriptor;
-import org.wyona.yanel.core.attributes.tracking.TrackingInformationV1;
 import org.wyona.yanel.core.navigation.Node;
 import org.wyona.yanel.core.navigation.Sitetree;
 import org.wyona.yanel.core.serialization.SerializerFactory;
@@ -103,6 +101,7 @@
  */
 public class YanelServlet extends HttpServlet {
 
+    private static final long serialVersionUID = 2270590853284570902L;
     private static Logger log = Logger.getLogger(YanelServlet.class);
     private static Logger logAccess = Logger.getLogger(AccessLog.CATEGORY);
     private static Logger log404 = Logger.getLogger("404");
@@ -232,12 +231,16 @@
     protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         // NOTE: Do not add code outside the try-catch block, because otherwise exceptions won't be logged
         try {
-            //String httpAcceptMediaTypes = request.getHeader("Accept");
-            //String httpAcceptLanguage = request.getHeader("Accept-Language");
+            String httpAcceptMediaTypes = request.getHeader("Accept");
+            String httpAcceptLanguage = request.getHeader("Accept-Language");
 
             String yanelUsecase = request.getParameter(YANEL_USECASE);
             if(yanelUsecase != null && yanelUsecase.equals("logout")) {
-                AutoLogin.removeCookie(request, response);
+                try {
+                    AutoLogin.disableAutoLogin(request, response, getRealm(request).getRepository());
+                } catch (Exception e) {
+                    log.error("Exception while disabling AutoLogin feature: "+e,e);
+                }
                 // INFO: Logout from Yanel
                 if(doLogout(request, response) != null) return;
             } else if(yanelUsecase != null && yanelUsecase.equals("create")) { // TODO: Why does that not go through access control?
@@ -448,7 +451,6 @@
 
         String usecase = request.getParameter(YANEL_RESOURCE_USECASE);
         Resource res = null;
-        TrackingInformationV1 trackInfo = null;
         long lastModified = -1;
         long size = -1;
 
@@ -457,15 +459,7 @@
             Environment environment = getEnvironment(request, response);
             res = getResource(request, response);
             if (res != null) {
-                if (ResourceAttributeHelper.hasAttributeImplemented(res, "Trackable", "1")) {
-                    //log.debug("Do track: " + res.getPath());
-                    trackInfo = new TrackingInformationV1();
-                    ((org.wyona.yanel.core.api.attributes.TrackableV1) res).doTrack(trackInfo);
-                //} else {
-                //    log.debug("Resource '" + res.getPath() + "' is not trackable.");
-                }
 
-
                 // START introspection generation
                 if (usecase != null && usecase.equals("introspection")) {
                     sendIntrospectionAsResponse(res, doc, rootElement, request, response);
@@ -622,7 +616,7 @@
                                         response.setContentType("application/xml");
                                         response.setStatus(javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                                         // TODO: Checkout date and break-lock (optional)
-                                        response.getWriter().print(XMLExceptionV1.getCheckoutException(eMessage, res.getPath(), checkoutUserID, null));
+                                        //response.getWriter().print(XMLExceptionV1.getCheckoutException(eMessage, res.getPath(), checkoutUserID, null));
                                         return;
                                     } else {
                                         throw new Exception("Resource '" + res.getPath() + "' is already checked out by another user: " + checkoutUserID);
@@ -671,7 +665,7 @@
 
 
         if (view != null) {
-            if (generateResponse(view, res, request, response, doc, size, lastModified, trackInfo) != null) return;
+            if (generateResponse(view, res, request, response, doc, size, lastModified) != null) return;
         } else {
             String message = "View is null!";
             Element exceptionElement = (Element) rootElement.appendChild(doc.createElementNS(NAMESPACE, "exception"));
@@ -999,7 +993,7 @@
                 response.setContentType("application/xml; charset=" + DEFAULT_ENCODING);
                 response.setStatus(javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                 PrintWriter w = response.getWriter();
-                w.print(XMLExceptionV1.getDefaultException(XMLExceptionV1.DATA_NOT_WELL_FORMED, e.getMessage()));
+                //w.print(XMLExceptionV1.getDefaultException(XMLExceptionV1.DATA_NOT_WELL_FORMED, e.getMessage()));
                 return;
             }
         } else {
@@ -1034,7 +1028,7 @@
             response.setStatus(javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
             PrintWriter w = response.getWriter();
             // TODO: This is not really a 'checkin' problem, but rather a general 'save-data' problem, but the Neutron spec does not support such a type: http://neutron.wyona.org/draft-neutron-protocol-v0.html#rfc.section.8
-            w.print(XMLExceptionV1.getDefaultException(XMLExceptionV1.CHECKIN, message));
+            //w.print(XMLExceptionV1.getDefaultException(XMLExceptionV1.CHECKIN, message));
         }
         
         if (doCheckin) {
@@ -1073,15 +1067,21 @@
 
         // Auto-Login
         if (identity == null || (identity != null && identity.isWorld())) {
-            Cookie autoLoginCookie = AutoLogin.getCookie(request);
-            if (autoLoginCookie != null) {
-                try {
-                    if (AutoLogin.matchCookie(autoLoginCookie, realm.getRepository())) {
-                        // TODO: login
+            log.debug("Autologin: not logged in");
+            try {
+                if (AutoLogin.doAutoLogin(request, response, realm)) {
+                    log.debug("We perform an autologin!");
+                    String username = AutoLogin.getUsername(request);
+                    if (username != null) {
+                        User user = realm.getIdentityManager().getUserManager().getUser(username);
+                        setIdentity(new Identity(user, user.getEmail()), request.getSession(), realm);
                     }
-                } catch(Exception e) {
-                    log.error(e, e);
+
+                } else {
+                    log.debug("We do not login the user automatically.");
                 }
+            } catch(Exception e) {
+                log.error(e, e);
             }
         }
 
@@ -1148,7 +1148,7 @@
             if(doAuthenticate(request, response) != null) {
                 log.info("Return response of web authenticator.");
                 /*
-		  NOTE: Such a response can have different reasons:
+          NOTE: Such a response can have different reasons:
                         - Either no credentials provided yet and web authenticator is generating a response to fetch credentials
                         - Or authentication failed and web authenticator is resending response to fetch again credentials");
                         - Or authentication was successful and web authenticator sends a redirect
@@ -1158,7 +1158,7 @@
                     if (usecase!= null && !usecase.equals("introspection")) {
                         log.debug("Ignore introspection requests ...");
                     } else {
-                        doLogAccess(request, response, null, null);
+                        doLogAccess(request, response, null);
                     }
                 }
 
@@ -1375,11 +1375,11 @@
     private HttpServletResponse doAuthenticate(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         try {
             // TODO/TBD: In the case of HTTP-BASIC/DIGEST one needs to check authentication with every request
-	    // TODO: enhance API with flag, e.g. session-based="true/false"
-	    // WARNING: One needs to separate doAuthenticate from the login screen generation!
+        // TODO: enhance API with flag, e.g. session-based="true/false"
+        // WARNING: One needs to separate doAuthenticate from the login screen generation!
             //if (getIdentity(request) != null) return null;
 
-	    WebAuthenticator wa = map.getRealm(request.getServletPath()).getWebAuthenticator();
+        WebAuthenticator wa = map.getRealm(request.getServletPath()).getWebAuthenticator();
             return wa.doAuthenticate(request, response, map, reservedPrefix, xsltLoginScreenDefault, servletContextRealPath, sslPort);
         } catch (Exception e) {
             log.error(e.getMessage(), e);
@@ -1770,7 +1770,7 @@
                 log.warn("No such authorization type implemented: " + authorizationHeader);
             }
         }
-	
+    
         if(log.isDebugEnabled()) log.debug("No identity yet (Neither session nor header based! Identity is set to WORLD!)");
         // TBD: Should add world identity to the session?
         return new Identity();
@@ -1816,9 +1816,7 @@
         }
         View view = ((ViewableV2) resource).getView(viewId);
         if (view != null) {
-            log.warn("TODO: Tracking not implemented yet: " + resource.getPath());
-            TrackingInformationV1 trackInfo = null;
-            if (generateResponse(view, resource, request, response, getDocument(NAMESPACE, "yanel"), -1, -1, trackInfo) != null) return true;
+            if (generateResponse(view, resource, request, response, getDocument(NAMESPACE, "yanel"), -1, -1) != null) return true;
         }
         return false;
     }
@@ -1978,20 +1976,19 @@
     /**
      * Generate response from a resource view, whereas it will be checked first if the resource already wrote the response (if so, then just return)
      * @param res Resource which handles the request in order to generate a response
-     * @param trackInfo Tracking information bean which might be updated by resource if resource is implementing trackable
      */
-    private HttpServletResponse generateResponse(View view, Resource res, HttpServletRequest request, HttpServletResponse response, Document doc, long size, long lastModified, TrackingInformationV1 trackInfo) throws ServletException, IOException {
-        //log.debug("Generate response: " + res.getPath());
-
+    private HttpServletResponse generateResponse(View view, Resource res, HttpServletRequest request, HttpServletResponse response, Document doc, long size, long lastModified) throws ServletException, IOException {
         // TODO: There seem like no header fields are being set (e.g. Content-Length, ...). Please see below ...
 
-        // INFO: Check if viewable resource has already created a response
+        //log.debug("Generate response: " + res.getPath());
+
+        // Check if viewable resource has already created a response
         if (!view.isResponse()) {
             if(logAccessEnabled) {
                 if (view.getMimeType() != null) {
                     if (isMimeTypeOk(view.getMimeType())) {
                         //log.debug("Mime type '" + view.getMimeType() + "' of request: " + request.getServletPath() + "?" + request.getQueryString());
-                        doLogAccess(request, response, res, trackInfo);
+                        doLogAccess(request, response, res);
                     }
                 }
             }
@@ -2023,11 +2020,12 @@
             }
         }
 
+
         if(logAccessEnabled) {
             if (mimeType != null) {
                 if (isMimeTypeOk(mimeType)) {
                     //log.debug("Mime type '" + mimeType + "' of request: " + request.getServletPath() + "?" + request.getQueryString());
-                    doLogAccess(request, response, res, trackInfo);
+                    doLogAccess(request, response, res);
                 }
             }
         }
@@ -2101,6 +2099,7 @@
                     if (ifModifiedSince != -1) {
                         if (res instanceof ModifiableV2) {
                             long resourceLastMod = ((ModifiableV2)res).getLastModified();
+//                            long resourceLastMod = new Date().getTime();
                             //log.debug(resourceLastMod + " " +  ifModifiedSince);
                             if (resourceLastMod <= ifModifiedSince) {
                                 response.setStatus(javax.servlet.http.HttpServletResponse.SC_NOT_MODIFIED);
@@ -2498,9 +2497,8 @@
     /**
      * Log browser history of each user
      * @param resource Resource which handles the request
-     * @param trackInfo Tracking information bean
      */
-    private void doLogAccess(HttpServletRequest request, HttpServletResponse response, Resource resource, TrackingInformationV1 trackInfo) {
+    private void doLogAccess(HttpServletRequest request, HttpServletResponse response, Resource resource) {
         // TBD: What about a cluster, performance/scalability? See for example http://www.oreillynet.com/cs/user/view/cs_msg/17399 (also see Tomcat conf/server.xml <Valve className="AccessLogValve" and className="FastCommonAccessLogValve")
         // See apache-tomcat-5.5.33/logs/localhost_access_log.2009-11-07.txt
         // 127.0.0.1 - - [07/Nov/2009:01:24:09 +0100] "GET /yanel/from-scratch-realm/de/index.html HTTP/1.1" 200 4464
@@ -2536,34 +2534,7 @@
                 log.debug("Resource is null because access was probably denied: " + request.getServletPath());
             }
 
-            String accessLogMessage;
-            if (trackInfo != null) {
-                String[] trackingTags = trackInfo.getTags();
-                if (trackingTags != null && trackingTags.length > 0) {
-                    accessLogMessage = AccessLog.getLogMessage(request, response, realm.getID(), trackingTags);
-                } else {
-                    accessLogMessage = AccessLog.getLogMessage(request, response, realm.getID(), tags);
-                }
-
-                String pageType = trackInfo.getPageType();
-                if (pageType != null) {
-                    accessLogMessage = accessLogMessage + AccessLog.encodeLogField("pt", pageType);
-                }
-
-                String requestAction = trackInfo.getRequestAction();
-                if (requestAction != null) {
-                    accessLogMessage = accessLogMessage + AccessLog.encodeLogField("ra", requestAction);
-                }
-
-                HashMap<String, String> customFields = trackInfo.getCustomFields();
-                if (customFields != null) {
-                    for (java.util.Map.Entry field : customFields.entrySet()) {
-                        accessLogMessage = accessLogMessage + AccessLog.encodeLogField((String) field.getKey(), (String) field.getValue());
-                    }
-                }
-            } else {
-                accessLogMessage = AccessLog.getLogMessage(request, response, realm.getID(), tags);
-            }
+            String accessLogMessage = AccessLog.getLogMessage(request, response, realm.getID(), tags);
             
             // TBD/TODO: What if user has logged out, but still has a persistent cookie?!
             Identity identity = getIdentity(request, map);
@@ -2583,12 +2554,6 @@
                 // 127.0.0.1 - - [07/Nov/2009:01:24:09 +0100] "GET /yanel/from-scratch-realm/de/index.html HTTP/1.1" 200 4464
 */
             }
-
-            String httpAcceptLanguage = request.getHeader("Accept-Language");
-            if (httpAcceptLanguage != null) {
-                accessLogMessage = accessLogMessage + AccessLog.encodeLogField("a-lang", httpAcceptLanguage);
-            }
-
             logAccess.info(accessLogMessage);
 
             //log.debug("Referer: " + request.getHeader(HTTP_REFERRER));


More information about the Yanel-development mailing list