[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