[Yanel-dev] OpenID patch

Evaldas Taroza etaroza at optaros.com
Tue Jan 15 17:11:05 CET 2008


Hi everyone,

I did a simple implementation for the logging in with an OpenID. After =

applying the patch *joid.jar and tsik.jar* must be in the dependencies. =

I believe these libraries should be put into Wyona's Maven repository.

There is several issues though:
1. When someone logs in with an OpenID a respective user in Yanel is =

created. It is not clear which policies this user should have nor to =

which group it should belong... So now I preinsert openid-yanel users =

into some groups, e.g. I put http---evaldas.taroza.myopenid.com into =

ac-identities/groups/editor.xml and then when I log in with my =

http://evaldas.taroza.myopenid.com I get the editor privileges. (Note =

that I the Yanel user id is made out of OpenID by replacing special =

characters, like , * : / & by a dash)

2. When I press "Deny" on the OpenID provider and then try to =

reauthenticate again, I cannot do that... I posted a question on Joid =

mailing list, hopefully there will be some help from there.

So Michael, can you commit that? And I think we should think about =

solution to the problem (1).

Cheers,

Evaldas
-------------- next part --------------
Index: src/java/org/wyona/yanel/servlet/security/impl/DefaultWebAuthenticat=
orImpl.java
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- src/java/org/wyona/yanel/servlet/security/impl/DefaultWebAuthenticatorI=
mpl.java	(revision 30347)
+++ src/java/org/wyona/yanel/servlet/security/impl/DefaultWebAuthenticatorI=
mpl.java	(working copy)
@@ -1,37 +1,34 @@
 package org.wyona.yanel.servlet.security.impl;
 =

-import org.wyona.yanel.core.map.Map;
-import org.wyona.yanel.core.map.Realm;
-import org.wyona.yanel.servlet.IdentityMap;
-import org.wyona.yanel.servlet.YanelServlet;
-import org.wyona.yanel.core.api.security.WebAuthenticator;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.URL;
+import java.util.Iterator;
 =

-import org.wyona.security.core.api.AccessManagementException;
-import org.wyona.security.core.ExpiredIdentityException;
-import org.wyona.security.core.api.Identity;
-import org.wyona.security.core.api.User;
-
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.PrintWriter;
-
 import javax.xml.transform.Transformer;
 import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.stream.StreamSource;
 =

-import java.net.URL;
-
-import org.w3c.dom.Element;
-
-import org.apache.log4j.Category;
-
 import org.apache.avalon.framework.configuration.Configuration;
 import org.apache.avalon.framework.configuration.DefaultConfigurationBuild=
er;
+import org.apache.log4j.Category;
+import org.verisign.joid.consumer.OpenIdFilter;
+import org.verisign.joid.util.UrlUtils;
+import org.w3c.dom.Element;
+import org.wyona.security.core.ExpiredIdentityException;
+import org.wyona.security.core.api.AccessManagementException;
+import org.wyona.security.core.api.Identity;
+import org.wyona.security.core.api.User;
+import org.wyona.yanel.core.api.security.WebAuthenticator;
+import org.wyona.yanel.core.map.Map;
+import org.wyona.yanel.core.map.Realm;
+import org.wyona.yanel.servlet.IdentityMap;
+import org.wyona.yanel.servlet.YanelServlet;
 =

 /**
  *
@@ -48,7 +45,7 @@
     }
 =

     /**
-     *
+     * This method is called from within the YanelServlet whenever authent=
ication is needed. Normally it is the case when the user enters credentials=
 into the login form.
      */
     public HttpServletResponse doAuthenticate(HttpServletRequest request, =
HttpServletResponse response, Map map, String reservedPrefix, String xsltLo=
ginScreenDefault, String servletContextRealPath, String sslPort) throws Ser=
vletException, IOException {
         try {
@@ -91,13 +88,109 @@
                     return response;
                 }
             } else if (openID !=3D null) {
+                // NOTE[et]: there is actually an issue with the OpenID pr=
ovider, when I press "Deny" there and then try to reauthenticate
+                // the FullUrl will be about denial, so consumer will fail=
. I don't know where is the issue and how to work around this
+                =

+                String returnTo =3D UrlUtils.getFullUrl(request);
+                if (null !=3D openID && !openID.startsWith("http:")) {
+                    openID =3D "http://" + openID;
+                }
+                String trustRoot =3D returnTo;
+                =

+                String s =3D OpenIdFilter.joid().getAuthUrl(openID, return=
To, trustRoot);
+                response.sendRedirect(s);
+                =

                 // TODO: Implement OpenID ... (see for instance http://cod=
e.google.com/p/joid/)
-                log.warn("OpenID implementation not finished yet: [" + ope=
nID + "]");
-                getXHTMLAuthenticationForm(request, response, realm, "Logi=
n failed because OpenID implementation is not finished yet!", reservedPrefi=
x, xsltLoginScreenDefault, servletContextRealPath, sslPort, map);
-                return response;
+//                log.warn("OpenID implementation not finished yet: [" + o=
penID + "]");
+//                getXHTMLAuthenticationForm(request, response, realm, "Lo=
gin failed because OpenID implementation is not finished yet!", reservedPre=
fix, xsltLoginScreenDefault, servletContextRealPath, sslPort, map);
+                return null;
             } else {
                 if (log.isDebugEnabled()) log.debug("No form based authent=
ication request.");
             }
+            =

+            {   // Check if the user is logged in with the OpenID
+                =

+                HttpSession session =3D null;
+                String userURL =3D null;
+                if((userURL =3D OpenIdFilter.getCurrentUser((session =3D r=
equest.getSession()))) !=3D null){
+                    // logged in with the OpenID
+                    log.debug("Logged in with OpenID:"+OpenIdFilter.getCur=
rentUser(request.getSession()));
+                    =

+                    class PasswordGenerator{
+                        private int length =3D 9;
+                        private PasswordGenerator(){}
+                        private PasswordGenerator(int length){this.length =
=3D length;}
+                        public String createPassword(){
+                            StringBuffer password =3D new StringBuffer(len=
gth);
+                            for (int i =3D 0; i < 9; i++) {
+                                if(Math.random() < 0.4){
+                                    // Number
+                                    password.append((int)(Math.random()*(5=
7 - 48 + 1)) + 48);
+                                }else if(Math.random() >=3D 0.4 && Math.ra=
ndom() < 0.7){
+                                    // Capital letter
+                                    password.append((int)(Math.random()*(9=
0 - 65 + 1)) + 65);
+                                }else if(Math.random() >=3D 0.7){
+                                    // Not capital letter
+                                    password.append((int)(Math.random()*(1=
22 - 97 + 1)) + 97);
+                                } =

+                            }
+                            return password.toString();
+                        }
+                    }
+                    =

+                    // Replace the chars that don't allow to create a files
+                    String userID =3D userURL.replace('/', '-');
+                    userID =3D userID.replace(':', '-');
+                    userID =3D userID.replace('?', '-');
+                    userID =3D userID.replace('&', '-');
+                    userID =3D userID.replace('*', '-');
+                    userID =3D userID.replace('|', '-');
+                    // TODO: maybe there are dissallowed chars, but mind b=
ackwards compatibility
+                    =

+                    User user =3D null;
+                    if((user =3D realm.getIdentityManager().getUserManager=
().getUser(userID, true)) =3D=3D null){
+                        user =3D realm.getIdentityManager().getUserManager=
().createUser(userID, userURL, "email at not.provided", new PasswordGenerator(=
8).createPassword());
+                        =

+                        // Save the user, otherwise it will be lost on fir=
st refresh of the user manager
+                        user.save();
+                        =

+                        // Refresh to see the groups for this user because=
 they are inserted manually
+                        //TODO: avoid this workaround
+                        user =3D realm.getIdentityManager().getUserManager=
().getUser(userID, true);
+                    }
+                    =

+                    //TODO: the user must have some policies assigned, or =
it must belong to some group
+                    //It is currently not clear how to do that, (no API fo=
r that still?) =

+                    //so the user (e.g. http---evaldas.taroza.myopenid.com=
) should be inserted to some group manually in order to login with an OpenID
+                    =

+                    // Register identity
+                    IdentityMap identityMap =3D (IdentityMap)session.getAt=
tribute(YanelServlet.IDENTITY_MAP_KEY);
+                    if (identityMap =3D=3D null) {
+                        identityMap =3D new IdentityMap();
+                        session.setAttribute(YanelServlet.IDENTITY_MAP_KEY=
, identityMap);
+                        identityMap.put(realm.getID(), new Identity(user));
+                    }else{
+                        // Check if the openID identity is registered for =
Yanel
+                        boolean registered =3D false;
+                        for (Iterator i =3D identityMap.values().iterator(=
); i.hasNext() && !registered;) {
+                            Identity identity =3D (Identity) i.next();
+                            if(identity.getUsername().equals(userID)){
+                                registered =3D true;
+                            }
+                        }
+                        if(!registered){
+                            identityMap.put(realm.getID(), new Identity(us=
er));
+                        }
+                        =

+                    }
+                    =

+                    // Yanel user was created, consumer must be disconnect=
ed from the OpenID provider
+                    // This is also needed to avoid loops of redirection
+                    OpenIdFilter.logout(session);
+                    =

+                    return null;
+                }
+            }
 =

             // Check for Neutron-Auth based authentication
             String yanelUsecase =3D request.getParameter("yanel.usecase");
Index: WEB-INF/web.xml
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- WEB-INF/web.xml	(revision 30347)
+++ WEB-INF/web.xml	(working copy)
@@ -16,6 +16,30 @@
   <display-name>Yanel</display-name>
   <description>Yanel</description>
 =

+    <filter>
+        <description>This filter (for Consumer side) automatically parses =
OpenID responses and sets the user's identity in the session.</description>
+        <filter-name>OpenIdFilter</filter-name>
+        <filter-class>org.verisign.joid.consumer.OpenIdFilter</filter-clas=
s>
+    <init-param>
+      <description>Optional. Will store the identity url in a cookie under=
 "openid.identity" if set to true.</description>
+      <param-name>saveInCookie</param-name>
+      <param-value>false</param-value>
+    </init-param>
+    <!--
+    <init-param>
+      <param-name>cookieDomain</param-name>
+      <param-value>www.mydomain.com</param-value>
+      <description>Optional. Domain to store cookie based on RFC 2109. Def=
aults to current context.</description>
+    </init-param>
+    =

+        <init-param>
+      <param-name>ignorePaths</param-name>
+      <param-value>/login</param-value>
+      <description>Optional. Will not apply filter to the paths set here. =
Comma delimited.</description>
+    </init-param>
+        -->
+    </filter>
+ =

   <servlet>
     <servlet-name>YanelServlet</servlet-name>
     <servlet-class>org.wyona.yanel.servlet.YanelServlet</servlet-class>
@@ -45,7 +69,12 @@
      <param-value>2</param-value>
     </init-param>
   </servlet>
-
+   =

+  <filter-mapping>
+    <filter-name>OpenIdFilter</filter-name>
+    <url-pattern>/*</url-pattern>
+  </filter-mapping>
+   =

   <servlet-mapping>
     <servlet-name>YanelServlet</servlet-name>
     <url-pattern>/</url-pattern>


More information about the Yanel-development mailing list