<?xml version="1.0" encoding="utf-8" ?>

<rss version="2.0" 
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:admin="http://webns.net/mvcb/"
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
   xmlns:wfw="http://wellformedweb.org/CommentAPI/"
   xmlns:content="http://purl.org/rss/1.0/modules/content/"
   >
<channel>
    
    <title>A River of Words - Tools and Languages</title>
    <link>http://blog.joeysmith.com/</link>
    <description>Drowning In Stupid</description>
    <dc:language>en</dc:language>
    <generator>Serendipity 1.5.5 - http://www.s9y.org/</generator>
    <pubDate>Tue, 12 Jul 2011 17:44:00 GMT</pubDate>

    <image>
        <url>http://blog.joeysmith.com/templates/default/img/s9y_banner_small.png</url>
        <title>RSS: A River of Words - Tools and Languages - Drowning In Stupid</title>
        <link>http://blog.joeysmith.com/</link>
        <width>100</width>
        <height>21</height>
    </image>

<item>
    <title>Pylons &quot;Classic&quot; (pre-pyramid) and LDAP Auth</title>
    <link>http://blog.joeysmith.com/articles/114.html</link>
            <category>Python</category>
    
    <comments>http://blog.joeysmith.com/articles/114.html#comments</comments>
    <wfw:comment>http://blog.joeysmith.com/wfwcomment.php?cid=114</wfw:comment>

    <slash:comments>1</slash:comments>
    <wfw:commentRss>http://blog.joeysmith.com/rss.php?version=2.0&amp;type=comments&amp;cid=114</wfw:commentRss>
    

    <author>nospam@example.com (TML)</author>
    <content:encoded>
    	&lt;p&gt;It took me a long time to figure this out, I didn&amp;#8217;t want it to end up locked in my head, so here&amp;#8217;s a rough guide on how I managed to get a pylons 0.9.7 project to do &lt;span class=&quot;caps&quot;&gt;LDAP&lt;/span&gt; authentication. All of the below is done in config/middleware.py.&lt;/p&gt;

	&lt;p&gt;The key points are:
	&lt;ol&gt;
		&lt;li&gt;&amp;#8220;import ldap&amp;#8221; (for the obvious reason) and &amp;#8220;from paste.auth.basic import AuthBasicHandler&amp;#8221;&lt;/li&gt;
		&lt;li&gt;Wrap the stacked &lt;span class=&quot;caps&quot;&gt;WSGI&lt;/span&gt; &amp;#8216;app&amp;#8217; object in the AuthBasicHandler you just imported: &lt;code&gt;app = AuthBasicHandler(app, &amp;#39;The value you want to appear on the browser dialog box&amp;#39;, yourAuthFunctionHere)&lt;/code&gt;&lt;/li&gt;
		&lt;li&gt;Define an auth function &amp;#8220;yourAuthFunctionHere(requestEnvironment, username, password)&amp;#8221;. Some tricky bits:
	&lt;ol&gt;
		&lt;li&gt;If this function returns &amp;#8220;True&amp;#8221;, the request will proceed and there will be a new key in the Request object named &amp;#8216;REMOTE_USER&amp;#8217; that contains the passed username.&lt;/li&gt;
		&lt;li&gt;If this function returns &amp;#8220;False&amp;#8221;, the user will be prompted again until it succeeds. (I should probably find a way to limit these so people cannot just keep guessing.)&lt;/li&gt;
		&lt;li&gt;&lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/pypi.python.org/pypi/python-ldap/2.4.1&#039;);&quot;  href=&quot;http://pypi.python.org/pypi/python-ldap/2.4.1&quot;&gt;Python&amp;#8217;s LDAP&lt;/a&gt; has some strange behaviours:&lt;/li&gt;
	&lt;ul&gt;
		&lt;li&gt;Do ldap.initialize outside the auth function or you will swamp the &lt;span class=&quot;caps&quot;&gt;LDAP&lt;/span&gt; server with bind requests&lt;/li&gt;
		&lt;li&gt;Use synchronous bind (&amp;#8216;bind_s&amp;#8217; as opposed to &amp;#8216;bind&amp;#8217;) &amp;#8211; asynchronous bind in the &lt;span class=&quot;caps&quot;&gt;WSGI&lt;/span&gt; middleware layer caused some really bizarre behaviour here, including segfaults&lt;/li&gt;
		&lt;li&gt;Trap ldap.INVALID_CREDENTIALS and return False when it is raised, or watch all invalid logins crash the server process&lt;/li&gt;
		&lt;li&gt;bind (and bind_s) return a tuple, if the first item in the tuple is int(97), the bind worked &amp;#8211; otherwise, they might have bound but as an anonymous user, and we need to fail&lt;/li&gt;
		&lt;li&gt;the second item in that tuple is a list of messages from the server &amp;#8211; I&amp;#8217;m not handling those at all today, becuase in the sole case we&amp;#8217;re interested in (97, or &amp;#8220;auth&amp;#8221;),  the messages appear to be blank in our environment &amp;#8211; there&amp;#8217;s no reason to believe this is consistent, and I should probably research this further at some point to provide meaningful feedback to the user on failed auth.&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;/ol&gt;&lt;/li&gt;
		&lt;li&gt;You can&amp;#8217;t touch the session from within the &lt;span class=&quot;caps&quot;&gt;WSGI&lt;/span&gt; middleware layer&lt;/li&gt;
	&lt;/ol&gt;&lt;/p&gt;

	&lt;p&gt;All of this was done because a new server in our datacenter doesn&amp;#8217;t have packages for the old build of Apache that we used to configure our &lt;span class=&quot;caps&quot;&gt;LDAP&lt;/span&gt; auth back in the day. I&amp;#8217;m actually quite pleased at how the new system works, and am glad to be rid of that Apache+&lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; millstone that&amp;#8217;s been lurking as a dependancy in all of our Pylons projects simply for the &lt;span class=&quot;caps&quot;&gt;LDAP&lt;/span&gt; authentication solution.&lt;/p&gt; 
    </content:encoded>

    <pubDate>Tue, 12 Jul 2011 11:27:57 -0600</pubDate>
    <guid isPermaLink="false">http://blog.joeysmith.com/articles/114.html</guid>
    
</item>
<item>
    <title>AlivePDF and Pylons</title>
    <link>http://blog.joeysmith.com/articles/111.html</link>
            <category>Python</category>
    
    <comments>http://blog.joeysmith.com/articles/111.html#comments</comments>
    <wfw:comment>http://blog.joeysmith.com/wfwcomment.php?cid=111</wfw:comment>

    <slash:comments>1</slash:comments>
    <wfw:commentRss>http://blog.joeysmith.com/rss.php?version=2.0&amp;type=comments&amp;cid=111</wfw:commentRss>
    

    <author>nospam@example.com (TML)</author>
    <content:encoded>
    	&lt;p&gt;I have a project at work where we are using Pylons/paster as the web service provider. One of the &amp;#8220;clients&amp;#8221; of this service is written in Flex/Flash, and had as a component the &lt;a onclick=&quot;javascript: pageTracker._trackPageview(&#039;/extlink/alivepdf.bytearray.org/&#039;);&quot;  href=&quot;http://alivepdf.bytearray.org/&quot;&gt;AlivePDF&lt;/a&gt; AS3 library for generating a static &lt;span class=&quot;caps&quot;&gt;PDF&lt;/span&gt; of the Flash content. &lt;/p&gt;

	&lt;p&gt;Unfortunately, because Flash cannot save content locally, in order to actually &lt;span class=&quot;caps&quot;&gt;GET&lt;/span&gt; this &lt;span class=&quot;caps&quot;&gt;PDF&lt;/span&gt; content back to the user, AlivePDF posts a byte array to the service and expects the service to bundle that as a &lt;span class=&quot;caps&quot;&gt;PDF&lt;/span&gt; and send it back. They provide a &amp;#8220;content.php&amp;#8221; file as an example &amp;#8211; which, frankly, is some pretty inscrutable code until you manage to figure out what it&amp;#8217;s working around. So when one of my employees (the one who selected AlivePDF in the first place) sent me the &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; file, it took as long to understand what he wanted as it did to come up with a Pylons solution. You can find the latter bit below &amp;#8211; replace ${service} and ${controller} with your actual values through-out, and trim the ellipses (they are there to indicate there may be additional context on either side of the line I&amp;#8217;m giving you):&lt;/p&gt;

	&lt;p&gt;&lt;code style=&quot;white-space: pre&quot;&gt;&lt;br /&gt;
${service}/config/routing.py:&lt;br /&gt;
def make_map():&lt;br /&gt;
...
	map.connect(&amp;#8217;/${controller}/create.php&amp;#8217;, controller=&amp;#8217;${controller}&amp;#8217;, action=&amp;#8216;pdf&amp;#8217;)     # put this before the default routes, if you have any&lt;br /&gt;
...&lt;/p&gt;

	&lt;p&gt;${service}/controllers/${controller}.py:&lt;br /&gt;
Class ${controller}(BaseController):&lt;br /&gt;
...
    def pdf(self):
        response.headers[&amp;#8216;Content-Type&amp;#8217;] = request.environ[&amp;#8216;CONTENT_TYPE&amp;#8217;]
        response.headers[&amp;#8216;Content-Disposition&amp;#8217;] = &amp;#8216;inline; filename=&amp;#8221;%s&amp;#8221;&amp;#8217; % request.GET[&amp;#8216;name&amp;#8217;]
        return request.environ[&amp;#8216;wsgi.input&amp;#8217;].read(int(request.environ[&amp;#8216;CONTENT_LENGTH&amp;#8217;]))&lt;br /&gt;
...&lt;br /&gt;
&lt;/code&gt;&lt;/p&gt; 
    </content:encoded>

    <pubDate>Tue, 05 Oct 2010 16:40:28 -0600</pubDate>
    <guid isPermaLink="false">http://blog.joeysmith.com/articles/111.html</guid>
    
</item>

</channel>
</rss>
