[Yanel-dev] OpenID patch

Michael Wechner michael.wechner at wyona.com
Wed Jan 16 09:32:32 CET 2008


Evaldas Taroza wrote:

> 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.


are there no other public maven where these libs are being hosted (e.g. 
ibiblio, maven itself)?

If not, what versions are these libs (?), such that we can add a version 
to the Wyona maven repo

>
> 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...


I would say none. Also I don't tunk such a user should be created by 
default, because it would mean a big security hole, but I understand it 
depends on the situation, e.g.

- NO: http://www.wyona.com/
- YES: http://foaf.wyona.org/

also how to configure the trusted openID providers.

How can we make this configurable or moderateable?

> 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)


I guess this would be custom and hence we need to provide a way that 
developers/integrators can change this.

>
>
> 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.


ok

>
> So Michael, can you commit that? And I think we should think about 
> solution to the problem (1).


yes, will commit as soon as we will have solved the issues which you 
describe above ;-)

Cheers

Michi

>
> Cheers,
>
> Evaldas
>
>------------------------------------------------------------------------
>
>Index: src/java/org/wyona/yanel/servlet/security/impl/DefaultWebAuthenticatorImpl.java
>===================================================================
>--- src/java/org/wyona/yanel/servlet/security/impl/DefaultWebAuthenticatorImpl.java	(revision 30347)
>+++ src/java/org/wyona/yanel/servlet/security/impl/DefaultWebAuthenticatorImpl.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.DefaultConfigurationBuilder;
>+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 authentication 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 xsltLoginScreenDefault, String servletContextRealPath, String sslPort) throws ServletException, IOException {
>         try {
>@@ -91,13 +88,109 @@
>                     return response;
>                 }
>             } else if (openID != null) {
>+                // NOTE[et]: there is actually an issue with the OpenID provider, 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 = UrlUtils.getFullUrl(request);
>+                if (null != openID && !openID.startsWith("http:")) {
>+                    openID = "http://" + openID;
>+                }
>+                String trustRoot = returnTo;
>+                
>+                String s = OpenIdFilter.joid().getAuthUrl(openID, returnTo, trustRoot);
>+                response.sendRedirect(s);
>+                
>                 // TODO: Implement OpenID ... (see for instance http://code.google.com/p/joid/)
>-                log.warn("OpenID implementation not finished yet: [" + openID + "]");
>-                getXHTMLAuthenticationForm(request, response, realm, "Login failed because OpenID implementation is not finished yet!", reservedPrefix, xsltLoginScreenDefault, servletContextRealPath, sslPort, map);
>-                return response;
>+//                log.warn("OpenID implementation not finished yet: [" + openID + "]");
>+//                getXHTMLAuthenticationForm(request, response, realm, "Login failed because OpenID implementation is not finished yet!", reservedPrefix, xsltLoginScreenDefault, servletContextRealPath, sslPort, map);
>+                return null;
>             } else {
>                 if (log.isDebugEnabled()) log.debug("No form based authentication request.");
>             }
>+            
>+            {   // Check if the user is logged in with the OpenID
>+                
>+                HttpSession session = null;
>+                String userURL = null;
>+                if((userURL = OpenIdFilter.getCurrentUser((session = request.getSession()))) != null){
>+                    // logged in with the OpenID
>+                    log.debug("Logged in with OpenID:"+OpenIdFilter.getCurrentUser(request.getSession()));
>+                    
>+                    class PasswordGenerator{
>+                        private int length = 9;
>+                        private PasswordGenerator(){}
>+                        private PasswordGenerator(int length){this.length = length;}
>+                        public String createPassword(){
>+                            StringBuffer password = new StringBuffer(length);
>+                            for (int i = 0; i < 9; i++) {
>+                                if(Math.random() < 0.4){
>+                                    // Number
>+                                    password.append((int)(Math.random()*(57 - 48 + 1)) + 48);
>+                                }else if(Math.random() >= 0.4 && Math.random() < 0.7){
>+                                    // Capital letter
>+                                    password.append((int)(Math.random()*(90 - 65 + 1)) + 65);
>+                                }else if(Math.random() >= 0.7){
>+                                    // Not capital letter
>+                                    password.append((int)(Math.random()*(122 - 97 + 1)) + 97);
>+                                } 
>+                            }
>+                            return password.toString();
>+                        }
>+                    }
>+                    
>+                    // Replace the chars that don't allow to create a files
>+                    String userID = userURL.replace('/', '-');
>+                    userID = userID.replace(':', '-');
>+                    userID = userID.replace('?', '-');
>+                    userID = userID.replace('&', '-');
>+                    userID = userID.replace('*', '-');
>+                    userID = userID.replace('|', '-');
>+                    // TODO: maybe there are dissallowed chars, but mind backwards compatibility
>+                    
>+                    User user = null;
>+                    if((user = realm.getIdentityManager().getUserManager().getUser(userID, true)) == null){
>+                        user = realm.getIdentityManager().getUserManager().createUser(userID, userURL, "email at not.provided", new PasswordGenerator(8).createPassword());
>+                        
>+                        // Save the user, otherwise it will be lost on first 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 = 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 for 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 = (IdentityMap)session.getAttribute(YanelServlet.IDENTITY_MAP_KEY);
>+                    if (identityMap == null) {
>+                        identityMap = 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 = false;
>+                        for (Iterator i = identityMap.values().iterator(); i.hasNext() && !registered;) {
>+                            Identity identity = (Identity) i.next();
>+                            if(identity.getUsername().equals(userID)){
>+                                registered = true;
>+                            }
>+                        }
>+                        if(!registered){
>+                            identityMap.put(realm.getID(), new Identity(user));
>+                        }
>+                        
>+                    }
>+                    
>+                    // Yanel user was created, consumer must be disconnected 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 = request.getParameter("yanel.usecase");
>Index: WEB-INF/web.xml
>===================================================================
>--- 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-class>
>+    <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. Defaults 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>
>  
>
>------------------------------------------------------------------------
>
>_______________________________________________
>Yanel-development mailing list
>Yanel-development at wyona.com
>http://lists.wyona.org/cgi-bin/mailman/listinfo/yanel-development
>  
>


-- 
Michael Wechner
Wyona      -   Open Source Content Management - Yanel, Yulup
http://www.wyona.com
michael.wechner at wyona.com, michi at apache.org
+41 44 272 91 61



More information about the Yanel-development mailing list