2017-07-25

Your Brain, a Temple or Sacred Place


I was reading the article How to consume News a couple of mornings ago, and the last point must have really resonated with me because my mind wondered on the drive to work.  The last point is:

■ Most of all, be kind and respectful to your brain. Treat it like you would treat your home or a temple or a sacred place. Control what goes in there with extreme prejudice. You have finite mental horsepower. Use it on things that are worth it.

So I thought, treat your mind like a temple, that's kind of like treating your body as a temple, where someone takes care of their body and what they put into it.  Eating healthy, or watching what you eat can have significant benefits.  Over the past couple of decades there has been a huge push towards eating healthy.  The opposite, junk food, and eating it regularly negatively affects your body and overall performance, just watch Super Size Me.  So junk food is bad for you and your body, is there a parallel for your brain and if so what would it be?

Let's think about junk food for a moment.  It generally has high amounts of sugar and/or fat, and our body craves it because it's high in energy.  Let's focus on sugar, where we get a burst of energy, a temporary high, followed by a low.  That can start a vicious cycle of highs and lows, including mood swings.

Can we make parallels between junk food and information and/or news?  Do we get the same highs and lows from fast breaking news?  The latest terror threat, scandal, etc.  Even the urge to look at an accident while you drive by somewhat seems to fit.  In some cases the high, adrenaline, is longer than a sugar high, but it is temporary.  We gossip about the latest thing, but then in a day or two that news is old, forgotten and didn't really benefit us in the long term.  And where do reality TV shows fit, immersed in someone else's trumped up and exaggerated reality instead of your own, or to escape your own (reminds me of an episode of Black Mirror).  We wasted a bunch of time and energy absorbing this unimportant information, and then we move onto the next thing.

What about our psyche or brains?  Negative news dominates in this day and age, is this similar to how junk food once dominated our diets.  Will we learn that this is unhealthy, and that we should be controlling/monitoring what our eyes and ears see and hear, how long will this take for us to learn.

Assuming there such a thing as junk information or junk news, we should be trying to avoid it.  Our brains can only handle a certain amount of information, so what if we're bombarding them with garbage.  Should we be trying to consume healthy information?  Will there be a push in society to control what gets to our eyes and ears just like we do our mouths?

2017-05-01

Adding Feature Switches to your Django Project in 10 Minutes

The first time I heard about feature switches was at a Winnipeg Agile Group meeting a year or two ago.  They peaked my interest immediately and seemed like a must when trying to practice DevOps.

I wanted to try them out on my own, so I did some investigating.  I have a Django hobby project and figured it would be a perfect target for trying out feature switches.  I started by writing down some of the features I though would be useful:

  • Stored in a database
  • Support changes on-the-fly
  • Global enable/disable
  • Must support multiple conditions
    • client IP address
    • user
    • group
    • date/time
  • Use them in several scenarios:
    • code (models.py, views.py in Django)
    • templates (Django)
    • entire projects (urls.py in Django)
Since Django has a lot of open source projects, I decided to do a Google search to see what's available.  I found a comparison with a bunch of old projects (+1 years since updated) that I avoided because they're likely not being maintained anymore, and decided to try out gargoyle since it had most (if not all) of the features I thought would be useful.  The original project is deprecated, however Yplan forked it and is actively maintaining the project.  So I downloaded the latest release and manually added it to my project.  I followed their suggestion and also added nexus, then later found I needed to add the dependencies modeldict and jsonfield (link to the project that worked).

However, when I logged in using my admin user and tried to add my first feature switch in the nexus UI, I repeatedly got the error "Enter valid JSON".  I tried a couple of different syntaxes thinking maybe it's expecting quotes, or doesn't support certain characters.  No luck.

Then I found a compatibility post, and figured maybe my jsonfield project is incompatible.  So I searched for a different version.  Fortunately the next version I tried fixed the problem, and I was off to the races.  I had my first feature switch saved in the database.

Next up, add some code that uses it.  Based on the really good gargoyle documentation, I made a slight modification to one of my views and the corresponding template.  Loading the page I found my feature switch looked like it was working.  To verify I toggled the feature switch back and forth in the nexus UI and refreshed the page each time.

Done.  That was too easy.

Please contact me if you have any questions, or are interested in the post and what I do.  


Below are most of the technical details:

def index(request):
    if (gargoyle.is_active('feature_key', request)):
        switched_variable = 'enabled'
    else:
        switched_variable = 'disabled'
    return render(request, 'project/index.html', {'switched_variable': switched_variable })
  • template additions:
   {% load gargoyle_tags %}
    {% ifswitch feature_key %}
        <DIV>SWITCH: ENABLED</DIV>
    {% else %}
        <DIV>SWITCH: DISABLED</DIV>
    {% endifswitch %}
    <DIV>Switch:{{ switched_variable }}</DIV>

2017-01-03

Liferay 6.1 - connecting to LDAP server

I've been working on a portal project recently using Liferay.  After getting Liferay installed on a local VM I was tasked with connecting it to an LDAP server for user authentication and importing groups for permissions.

Adding an LDAP server is simple.  Liferay has buttons for testing the connection, user import (with preview) and group import (with preview) that are extremely helpful.  Obviously, all of your settings will depend on the LDAP server you're connecting to.  In my case I didn't need to change any of the user and group default settings.  I did have to change the defaults for the connection.

I  found that using the Liferay control panel was the best way to connect to the LDAP server and determine the settings you need.  What you do with the settings after that really depends on your situation.  I'm a developer, and the project required extensive Liferay customizations.  Therefore, I moved the settings into an Ext plugin which we managed in SVN and deployed to multiple environments.  Alternatively, each environment can be manually however you may find this to be difficult to manage.
I wanted my own LDAP server because I needed to create my own set of users, groups, and have complete control over the structure.
I installed openLDAP locally and connected to it using jxplorer.  Then I created a bunch of groups and users by importing an ldif file.  My database looked good, and connecting/navigating it using jxplorer worked fine.  
To help verify/debug connecting to LDAP servers I used jxplorer, which is free and available for all of the common OSs.
 
The Technical Details

In my case the LDAP server is a test server, and was really easy to connect.  The hardest part was finding where the LDAP settings are located in the Liferay control panel. To get to the LDAP settings:
  1. Login to Liferay (http://localhost:8080, in my case test@liferay.com:test)
  2. Navigate to the control panel (Go To->Control Panel)
  3. Then under Portal in the left navigation, go to Authentication->LDAP

The options for LDAP are pretty self-explanatory:
  • Enabled - enable LDAP authentication
  • Required - require LDAP authentication (the only exception I'm aware of is the default admin user created when first logging into Liferay)
  • Import Enabled - import LDAP users and groups into Liferay
  • Export Enabled - export user and group changes made in Liferay to LDAP
  • Use LDAP Password Policy - I recommend selecting this, otherwise when users first login they will be forced to change their password
There are some useful LDAP options (for Liferay 6.1) that you can add to your portal-ext.properties file as well.  In my case I'm using the glassfish hosted version of Liferay 6.1, so my portal-ext.properties file is in liferay-portal-6.1.20-ee-ga2/glassfish-3.1.2/domains/domain1/applications/liferay-portal/WEB-INF/classes.  The following are some of the more useful settings that I used.
  • ldap.import.on.startup=false
  • ldap.import.interval=10
  • ldap.import.create.role.per.group = true
    • This is to create a role for each group, and add each group member to that role
    • I use this because all our permissions are role based
  • ldap.import.enabled=true
  • ldap.export.enabled=true
  • ldap.import.method=group
    • Only import users that are part of groups
    • The other option is user, i.e. only import groups that have users

In my case I needed to fill out my Base DN to import the users (dc=example,dc=com).
  •  Connection
    • Base Provider URL - ldap://192.168.1.55:389
    • Base DN - dc=example,dc=com
    • Principal - cn=Manager,dc=example,dc=com
    • Credentials - *****
  • Users
    • All defaults
  • Groups
    • All defaults
  • Export
    • Users DN - dc=example,dc=com
    • User Default Object Classes - top,inetOrgPerson,person
    • Groups DN - dc=example,dc=com
    • Group Default Object Classes - top,groupOfUniqueNames

Minor Issues I Encountered

The first issue you might run into is a certificate problem (if using ldaps).  Logging in will simply fail, and there won't be anything in the logs either.  To fix the problem you have to add the LDAP certificate to the Java cacerts store.

Then, Liferay could only connect.  Trying to import users and groups failed.  Eventually I determined that the problem was because I hadn't added the user I use to login to LDAP to the LDAP database.  I'm not sure why Liferay requires this and jxplorer doesn't, or for that matter why the user isn't automatically added to the database during installation/setup, but it's not.

During the import I ran into an problem.  I had issues (debugged continually restarting Liferay and using the liferay log file which was very time consuming) with screen names.  I simplified all my users so that they only contain alpha-numeric characters for all properties (cn, sn, uid, etc...).

Another possible issue you may run into is how LDAP is storing passwords.  By default Liferay seems to expect plain text, so that's what I'm using on my LDAP server.  Obviously you don't want to do this in production.  However, during development plain text is fine.

LDIF Snippet for Generating Users

Here's a snippet of the LDIF file I imported to setup my users and groups (LDIF->Import file in jxplorer):


dn: cn=u1,ou=users,dc=example,dc=com
cn: u1
sn: u1
objectClass: top
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
uid: u1
ou: users
givenName: u1
title: Mr.
mail: u1@
liferay.com
userpassword: u1

dn: cn=u2,ou=users,dc=example,dc=com
cn: u2
sn: u2
objectClass: top
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
uid: u2
ou: users
givenName: u2
title: Mr.
mail: u2@
liferay.com
userpassword: u2

dn: cn=u3,ou=users,dc=example,dc=com
cn: u3
sn: u3
objectClass: top
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
uid: u3
ou: users
givenName: u3
title: Mr.
mail: u3@liferay.com
userpassword: u3



dn: cn=g1,ou=Groups,dc=example,dc=com
objectClass: top
objectClass: groupOfUniqueNames
cn: g1
description: g1
uniquemember: cn=u1,ou=users,dc=example,dc=com
ou: groups

dn: cn=g2,ou=Groups,dc=example,dc=com
objectClass: top
objectClass: groupOfUniqueNames
cn: g2
description: g2
uniquemember: cn=u2,ou=users,dc=example,dc=com
ou: groups

dn: cn=g3,ou=Groups,dc=example,dc=com
objectClass: top
objectClass: groupOfUniqueNames
cn: g3
description: g3
uniquemember: cn=u3,ou=users,dc=example,dc=com
ou: groups