I apologize for the length of this message, but it's a topic that I believe to be of pretty wide interest and takes some explaining. I've built a servlet filter to intercept requests and demand cookies, redirecting to an enterprise SSO server if they're missing or invalid. Intended to provide the benefits of the SSO server to any J2EE-compliant servlet, it implements the servlet API methods HttpServletRequest.getUserPrincipal() and HttpServletRequest.isUserInRole() in a custom HttpServletRequestWrapper, which it initializes with the cookie-supplied information and then passes down the filter chain. An interface for writing custom adaptor classes is provided, and for XWiki I use it to customize the Principal to prepend "XWiki." to the value to be returned from Principal.getName(). All this is working splendidly for XWiki without the need for any custom versions of the authentication, rights, or group services, which was a design goal. Another design goal was to eliminate the need for manual registration of new users, either by themselves or administrators, by automatically registering any user not already registered before passing the request on. My filter provides two possible avenues for this: first, a second filter, which can be placed after the first, sends a generic POST request with all the cookie data to a custom-crafted URL, which is easy enough for an application such as XWiki to provide - or so it seems; second, adding code (in the application-specific adaptor interface mentioned above) to accomplish the task directly using the XWiki APIs. The first approach would have required a custom form, and it looked hard enough that I didn't try it, but most of all I couldn't work out how to get the correct permissions. Between that and the second, I created a URL object with which I formatted a GET request to the XWiki.RegisterNewUser page. That had significant problems, chief of which was determining whether the registration had actually worked - the HTTP status doesn't tell you, and I'd have to parse the response to guess the answer. Changing the form (which I had to do anyway) would make that easier, but I didn't like that answer either. So now I come to the second approach, which has so far been the most straightforward and appears, sometimes, to work, sort of. There is an XWiki.createUser() method that takes only the user name, a Map of object properties, the parent document name, the user profile document content, the user's privileges and the XWikiContext. All of those except the XWikiContext can be determined easily, but what goes into the context, and how it gets there, is another question, not to mention how I get my hands on the XWiki object running in the servlet to exercise that method. The second problem was attacked first. I found that after the servlet had handled its first request after starting, there was a property in the servlet context called "xwiki", and the currently running instance was its value. Bingo. As long as I could be sure I wasn't the first customer of the day, everything was great. And that would still work if it had to, but I still didn't like it. Putting a breakpoint in XWiki.init_xwiki(), which looked to be where the show began, showed me that it was called by a chain of (deprecated) constructors called, ultimately, by static method getXwiki. Now we're getting somewhere. But still I had to get some information into the XWikiContext which I had to pass to that method. I've had a bit of trouble getting to the method in the Struts packages that is called to initialize the context, and I'll probably find it eventually, but it's taking a long time and I'm hoping that someone has better understanding of Struts and J2EE and other such stuff and could shortcut my current route to understanding all of this, and/or to suggest a better approach. So, in short: 1) Where, if anywhere, can I jump into the XWiki APIs to initialize the context properly? and/or 2) If this is a stupid way to approach the problem, what would be a wiser one? Thanks in advance, as always, brain[sic]
On 2/20/07, THOMAS, BRIAN M (ATTSI) <[email protected]> wrote:
I apologize for the length of this message, but it's a topic that I believe to be of pretty wide interest and takes some explaining.
[snip] The first approach would have required a custom form, and it looked hard
enough that I didn't try it, but most of all I couldn't work out how to get the correct permissions. Between that and the second, I created a URL object with which I formatted a GET request to the XWiki.RegisterNewUser page. That had significant problems, chief of which was determining whether the registration had actually worked - the HTTP status doesn't tell you, and I'd have to parse the response to guess the answer. Changing the form (which I had to do anyway) would make that easier, but I didn't like that answer either.
We're already working on adding meaningful HTTP status codes. In a few days (if you want this) we can make registration return the proper status code. And I don't think you need to write a form, the right GET URL should work just fine. So, in short:
1) Where, if anywhere, can I jump into the XWiki APIs to initialize the context properly? and/or
Try looking inside .../xwiki/web/XWikiAction , that's a good starting point. Right now I'm in a hurry, so I don't have time to check myself. 2) If this is a stupid way to approach the problem, what would be a
wiser one?
If the registration page would return status codes, I'd say it is better to create a request. Thanks in advance, as always,
brain[sic]
Sergiu Dumitriu -- http://purl.org/net/sergiu
P.S.: Why CookieMonster? On 2/21/07, Sergiu Dumitriu <[email protected]> wrote:
On 2/20/07, THOMAS, BRIAN M (ATTSI) <[email protected]> wrote:
I apologize for the length of this message, but it's a topic that I believe to be of pretty wide interest and takes some explaining.
[snip]
The first approach would have required a custom form, and it looked hard
enough that I didn't try it, but most of all I couldn't work out how to get the correct permissions. Between that and the second, I created a URL object with which I formatted a GET request to the XWiki.RegisterNewUser page. That had significant problems, chief of which was determining whether the registration had actually worked - the HTTP status doesn't tell you, and I'd have to parse the response to guess the answer. Changing the form (which I had to do anyway) would make that easier, but I didn't like that answer either.
We're already working on adding meaningful HTTP status codes. In a few days (if you want this) we can make registration return the proper status code. And I don't think you need to write a form, the right GET URL should work just fine.
So, in short:
1) Where, if anywhere, can I jump into the XWiki APIs to initialize the context properly? and/or
Try looking inside .../xwiki/web/XWikiAction , that's a good starting point. Right now I'm in a hurry, so I don't have time to check myself.
2) If this is a stupid way to approach the problem, what would be a
wiser one?
If the registration page would return status codes, I'd say it is better to create a request.
Thanks in advance, as always,
brain[sic]
Sergiu Dumitriu
Sergiu: When I was thinking of how to describe what the filter did, I had this impression of Cookie Monster gobbling up cookies, crumbs flying everywhere, and yelling "Meee want Cooookieee!" and I couldn't resist. I even entertained the thought of naming the filter after him. I assume, perhaps inappropriately, that you know the fellow;but even in Europe the American children's program Sesame Street airs, does it not? brain[sic] -----Original Message----- From: Sergiu Dumitriu [mailto:[email protected]] Sent: Wednesday, February 21, 2007 5:32 AM To: [email protected] Subject: Re: [xwiki-users] CookieMonster P.S.: Why CookieMonster? On 2/21/07, Sergiu Dumitriu <[email protected]> wrote: On 2/20/07, THOMAS, BRIAN M (ATTSI) < [email protected] <mailto:[email protected]> > wrote: I apologize for the length of this message, but it's a topic that I believe to be of pretty wide interest and takes some explaining. [snip] The first approach would have required a custom form, and it looked hard enough that I didn't try it, but most of all I couldn't work out how to get the correct permissions. Between that and the second, I created a URL object with which I formatted a GET request to the XWiki.RegisterNewUser page. That had significant problems, chief of which was determining whether the registration had actually worked - the HTTP status doesn't tell you, and I'd have to parse the response to guess the answer. Changing the form (which I had to do anyway) would make that easier, but I didn't like that answer either. We're already working on adding meaningful HTTP status codes. In a few days (if you want this) we can make registration return the proper status code. And I don't think you need to write a form, the right GET URL should work just fine. So, in short: 1) Where, if anywhere, can I jump into the XWiki APIs to initialize the context properly? and/or Try looking inside .../xwiki/web/XWikiAction , that's a good starting point. Right now I'm in a hurry, so I don't have time to check myself. 2) If this is a stupid way to approach the problem, what would be a wiser one? If the registration page would return status codes, I'd say it is better to create a request. Thanks in advance, as always, brain[sic] Sergiu Dumitriu -- http://purl.org/net/sergiu -- http://purl.org/net/sergiu
Two things (not related to why I titled my message CookieMonster): First: Thanks, Sergiu, for the information, and the HTTP status code idea sounds good, although it may cause other people heartburn who expect a properly-rendered page to return HTTP_OK. I haven't looked at all the protocol's status codes thoroughly, though, and there might be some codes that are appropriate for an application error, and in particular, HTTP_UNAUTHORIZED(401) would probably be appropriate here. The biggest problem I had was how, from within a filter, to establish the authority to register a user. I probably don't need to comment on the appropriateness of using GET methods to effect changes; from the look of things the choice was probably a quick hack to get things done, since other update operations are not done that way. I do note that there is a "register" action path in the deployment descriptor, though the register link doesn't use it (and not only is register.vm written explicitly in French but it doesn't display the XWiki.XWikiUsers object's content), instead using "view" for a form submission, which apparently must use GET, because when I tried using POST, although I didn't get any errors, it didn't work and I abandoned the approach, mostly because I suspected that a lack of permission was to blame. Second: I did succeed in getting the correct context set, and the auto-registration from within the filter is now working quite well. Since it's easier to show than tell, here's the relevant code: private void setXWikiToRights(CSPCookieRequestWrapper req, HttpServletResponse rsp) throws ServletException { XWiki xwiki = null; XWikiContext context = null; try { /* this is a desperate attempt to get the correct context set * for XWiki in order to synch user privileges */ ServletContext sctx = req.getSession().getServletContext(); context = Utils.prepareContext("view", new XWikiServletRequest(req), new XWikiServletResponse(rsp), new XWikiServletContext(sctx)); xwiki = XWiki.getXWiki(context); } catch (XWikiException e2) { throw new ServletException("can't find XWiki instance", e2); } Map attrs = new HashMap(); Map authInfo = req.getUserPrincipal().getMap(); String content = "#includeForm(\"XWiki.XWikiUserSheet\")"; String userName = (String)authInfo.get(CSPCookieFilter.CSP_ATT_UID); attrs.put("email", authInfo.get(CSPCookieFilter.CSP_HR_EMAIL)); attrs.put("first_name", authInfo.get(CSPCookieFilter.CSP_HR_FIRST_NAME)); attrs.put("last_name", authInfo.get(CSPCookieFilter.CSP_HR_LAST_NAME)); try { xwiki.createUser(userName, attrs, "XWiki.WebHome", content, "edit", context); } catch (XWikiException e) { throw new ServletException("creating new user", e); } } As you suggested, I had indeed started with XWikiAction (or XWikiRequestProcessor, I forget which). The critical component was Utils.prepareContext which depended only on information I had readily to hand (well, almost; I had to modify the method signatures to pass in the response object, which had not previously been needed). I don't check for the existence of the user first, since createUser does that anyway, and more efficiently than I could, so I just invoke it unconditionally and ignore the return code. I probably should also ignore any exceptions too, counting on XWiki to handle any resulting problems. For another approach, the generic "synch filter" I described earlier, which simply sends a message with all of the parsed cookie values as tag-value pairs, might have worked with an XMLRPC request, but as with the "view" request to the RegisterNewUser page, I had a problem figuring out how to establish the necessary authority from within the filter. Generally, I think I agree that an HTTP request would be the best way to proceed; I just can't figure out how to get that authorization, since the filter can't assert any special identity from the client end of an HTTP connection merely because of its situation within the server itself. Allowing XWikiGuest to have "view" access to the registration page would seem to be a bad idea since, despite its security implications, that's what registration entails. I think I smell JIRA here... brain[sic] -----Original Message----- From: Sergiu Dumitriu [mailto:[email protected]] Sent: Wednesday, February 21, 2007 5:31 AM To: [email protected] Subject: Re: [xwiki-users] CookieMonster On 2/20/07, THOMAS, BRIAN M (ATTSI) <[email protected]> wrote: I apologize for the length of this message, but it's a topic that I believe to be of pretty wide interest and takes some explaining. [snip] The first approach would have required a custom form, and it looked hard enough that I didn't try it, but most of all I couldn't work out how to get the correct permissions. Between that and the second, I created a URL object with which I formatted a GET request to the XWiki.RegisterNewUser page. That had significant problems, chief of which was determining whether the registration had actually worked - the HTTP status doesn't tell you, and I'd have to parse the response to guess the answer. Changing the form (which I had to do anyway) would make that easier, but I didn't like that answer either. We're already working on adding meaningful HTTP status codes. In a few days (if you want this) we can make registration return the proper status code. And I don't think you need to write a form, the right GET URL should work just fine. So, in short: 1) Where, if anywhere, can I jump into the XWiki APIs to initialize the context properly? and/or Try looking inside .../xwiki/web/XWikiAction , that's a good starting point. Right now I'm in a hurry, so I don't have time to check myself. 2) If this is a stupid way to approach the problem, what would be a wiser one? If the registration page would return status codes, I'd say it is better to create a request. Thanks in advance, as always, brain[sic] Sergiu Dumitriu -- http://purl.org/net/sergiu
participants (2)
-
Sergiu Dumitriu -
THOMAS, BRIAN M (ATTSI)