[Zope] How to use "lower" attribute (or function) to catch
duplicate User IDs?
Dylan Reinhardt
zope@dylanreinhardt.com
Wed, 26 Feb 2003 21:32:14 -0800
At 07:58 PM 2/26/2003, Bob King wrote:
>I am new to Zope (less than a week) and I'm in the process of writing a
>small portal where users can sign themselves up.
Welcome.
>Right now it is working, but I have a few known problems - one of which is
>that my routine that checks for duplicate User IDs is case-sensitive (i.e.
>it would allow "bob","Bob" and "BOB" all to register).
That's the default behavior. If you want to make sure that doesn't happen,
you could do one of two things:
1. Force all user names to upper or lower case when you register them
2. Do a check for case-insensitive matches by single-casing your input and
testing it against a single-case version of each existing user.
The first solution is easy:
<dtml-call "manage_addUser(username.lower(), password, roles)">
The second a bit more cumbersome:
---------------
<dtml-call "REQUEST.set('matches', [])">
<dtml-in objectIds prefix=object>
<dtml-if "object_item.lower() == username.lower()">
<dtml-call "matches.append(1)">
</dtml-if>
</dtml-in>
<dtml-if matches>
Sorry, can't do that... we've got a name like <dtml-var username> already.
<dtml-else>
<dtml-call "manage_addUser(username, password, roles)">
</dtml-if>
---------------
>SECURITY QUESTION: - In order for this to work I had to set the security
>for on acl_users (for this folder) to "Manage users" for "Anonymous".
On first glance, that strikes me as a bad idea.
>Does this open up any way for someone to gain access directly to the
>acl_users folder?
Probably, though I don't have an exploit to offer you. In general, it's a
good idea to keep permissions as low as possible.
A better way to do this, generally, is to write a method that performs
*just* this privileged operation and give that method a proxy role that is
sufficient to perform the operation. You can then call that method in the
context of a regular user's privileges and they will still be able to do
whatever it is that method does. Proxy roles are well worth looking into
carefully, as they are a potential source of insecurity if written
uncautiously.
>1) How to track a "state" within a given DTML Document or Method? The
>Verify form is very cumbersome as I go through each "test" twice.
Within a method, the easiest way is to set a value in the REQUEST object, eg:
<dtml-call "REQUEST.set('some_var', some_python_expression)">
Between methods, there are ways of passing values:
<dtml-var "some_other_method(arg1=value1, arg2=value2)">
and placing variables into the namespace:
<dtml-let spam="'pork shoulder and ham'">
<dtml-var some_method>
</dtml-let>
Note the use of double and single quotes above... the outer double quotes
denote this as a Python expression, the inner single quotes convey that the
expression consists of a string value.
Tracking state between hits can be done in a number of ways, but I would
recommend a bit more reading first.
>If any errors exist, then I retest each parameter prior to redisplaying
>the form in order to flag the associated input box with an error
>message. I had to do that way because I couldn't figure out a way to
>accomplish it like this in DTML:
>
>If email-good then
> email-error=0
>else
> email-error=1
In DTML, it's:
<dtml-if email_good>
<dtml-call "REQUEST.set('email_error', 0)">
<dtml-else>
<dtml-call "REQUEST.set('email_error', 1)">
</dtml-if>
I would strongly advise you to get in the habit of using underscores
instead of dashes in your variable names (as shown above). When the
variable email-error is evaluated as part of a Python expression, it will
translate as "email minus error". There are ways around this, of course,
but the easiest thing to do as a beginner is to cultivate good naming habits.
>Then check, if all error values=0, submit the form, otherwise display the
>errors.
If you're performing a lot of these tests, I'd advise running them in
sequence instead of nesting them. It's heck of a lot easier to keep track
of it all and you're going to want to tell the user *all* the ways they
screwed up, not just the first one. :-)
Here's a quick sketch with a few different types of tests:
----------------
<!-- use a list object to collect errors -->
<dtml-call "REQUEST.set('errors', [])">
<dtml-unless expected_field_1>
<dtml-call "errors.append('You need to enter a value for Expected Field
1')">
</dtml-if>
<dtml-if "_.len(expected_field_2) < 3">
<dtml-call "errors.append('Expected Field 2 must contain at least three
letters or digits')">
</dtml-if>
<dtml-if "expected_field_3 in ['yo mamma', 'up yours', 'lamer']">
<dtml-call "errors.append('You need to provide a value for Expected
Field 3 that is less insulting')">
</dtml-if>
<!-- more tests go here -->
<dtml-if errors>
You had errors:<UL>
<dtml-in errors prefix=error>
<LI><dtml-var error_item></LI>
</dtml-in>
</UL>
<dtml-else>
<!-- call your form processing routine: -->
<dtml-call "some_thing(REQUEST.form)">
</dtml-if>
----------------
From here, I'd recommend some reading...
Dig in to The Zope Book and be aware that there are two versions available:
http://www.zope.org/Documentation/Books/ZopeBook/
I'd also highly recommend Dieter Maurer's book in progress:
http://www.dieter.handshake.de/pyprojects/zope/book/book.html
After that, feel free to let us know if you have more questions.
Dylan