{"id":72,"date":"2010-01-19T16:19:03","date_gmt":"2010-01-19T20:19:03","guid":{"rendered":"http:\/\/dashdrum.com\/blog\/?p=72"},"modified":"2010-01-19T16:19:03","modified_gmt":"2010-01-19T20:19:03","slug":"things-i-learned-about-django-authentication-and-django_cas-today","status":"publish","type":"post","link":"https:\/\/dashdrum.com\/blog\/2010\/01\/things-i-learned-about-django-authentication-and-django_cas-today\/","title":{"rendered":"Things I Learned About Django Authentication and django_cas Today"},"content":{"rendered":"<p>After programming a new site on my laptop (standalone web server, Django standard authentication), I moved it to the DEV server (Apache, CAS for authentication). Some things didn&#8217;t work the same.<\/p>\n<p>I had designed three security settings: Admin (can get to everything &#8211; superuser in Admin), Staff (can run reports, just a few permissions in Admin &#8211; marked as staff), and User (entry in Admin, but not staff and no permission, runs reports only).<\/p>\n<p>The views that displayed the reports use the <code>@login_required<\/code> decorator.<\/p>\n<p>Here&#8217;s the problem, and I saw this coming: any user who could sucessfully log in to CAS could run reports.  Since I&#8217;m using a campus wide CAS database, this included any campus staff member or student.  Not what I was going for.<\/p>\n<p>I had forgotten that <code>django_cas<\/code> adds every sucessfully loged in user as a User record in the Django Admin.  At that point, the user passes the <code>@login_required<\/code> test and can run those views.  <\/p>\n<p>My solution was two-fold.  Mark the User level records as staff, and replace the <code>@login_required <\/code>decorator with <code>@staff_member_required<\/code>.  Unfortunately, the system seemed to be using the Django internal login mechanism rather than CAS.  A little code inspection showed that the decorator wasn&#8217;t using a URL redirect to login, and instead was calling the Admin login function directly.  This bypasses both the <code>django_cas<\/code> middleware and the <code>LOGIN_URL<\/code> setting.<\/p>\n<p>Next, I tried using the <code>@user_passes_test decorator <\/code>testing for <code>user.is_staff<\/code> in place of <code>@staff_member_required<\/code> (which I will likely never use again).  This also worked in the standalone setting, but not with <code>django_cas<\/code> (kept throwing 500 errors).  I then switched to the versions of the <code>@user_passes_test<\/code> and <code>@login_required<\/code> decorators provided with <code>django_cas<\/code>, but then I kept getting 403 errors.<\/p>\n<p><strong>TIME FOR A LUNCH BREAK!!<\/strong><\/p>\n<p>After a sandwich and a quick walk, my refreshed mind reminded me to check to see if <code>django_cas<\/code> had been updated from v2.0.2 that I had installed.  Sure enough!  Version 2.0.3 specifically updated the decorators.  The <code>@user_passes_test<\/code> code had been updated to return a 403 only if a logged in user failed the test, and an unauthenticated user would get a proper login screen.  Furthermore, <code>@login_required<\/code> had been removed completely and replaced with an import of the standard django supplied version.  Even though I am currently unable to update the version on the DEV (or higher) servers, I saw what I needed to do.<\/p>\n<p>First, I changed my import statements to grab the correct decorators for the environment.<\/p>\n<pre>import settings\r\n\r\nif settings.USE_CAS:\r\n    from django_cas.decorators import user_passes_test\r\nelse:\r\n    from django.contrib.auth.decorators import user_passes_test\r\n    \r\nfrom django.contrib.auth.decorators import login_required<\/pre>\n<p>(Note that <code>USE_CAS<\/code> is a setting I&#8217;ve defined in the server specific settings file.) <\/p>\n<p>This code pulls in the proper <code>@user_passes_test<\/code> decorator, and the standard <code>@login_required<\/code> decorator, <\/p>\n<p>Next, for each veiw that needs protection, I implemented the decorators thusly:<\/p>\n<pre>@login_required   \r\n@user_passes_test(lambda u: u.is_staff)\r\ndef view_staff(request):\r\n    ...<\/pre>\n<p>Putting <code>@login_required<\/code> first forces a login if the user hasn&#8217;t, and then <code>@user_passes_test<\/code> checks for the staff attribute.<\/p>\n<p>With the changes in <code>django_cas v2.0.3<\/code>, the call to <code>@login_required<\/code> will no longer be necessary.  I hope to setup a project to update the version soon.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>After programming a new site on my laptop (standalone web server, Django standard authentication), I moved it to the DEV server (Apache, CAS for authentication). Some things didn&#8217;t work the same. I had designed three security settings: Admin (can get to everything &#8211; superuser in Admin), Staff (can run reports, just a few permissions in &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/dashdrum.com\/blog\/2010\/01\/things-i-learned-about-django-authentication-and-django_cas-today\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Things I Learned About Django Authentication and django_cas Today&#8221;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-72","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/posts\/72","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/comments?post=72"}],"version-history":[{"count":3,"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/posts\/72\/revisions"}],"predecessor-version":[{"id":75,"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/posts\/72\/revisions\/75"}],"wp:attachment":[{"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/media?parent=72"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/categories?post=72"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dashdrum.com\/blog\/wp-json\/wp\/v2\/tags?post=72"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}