[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