How to sort filter drop-downs in ActiveAdmin
Universal #2
guypaddock
One of the frustrating things about how ActiveAdmin displays associations in filter drop-downs is that they're not sorted by default.

Let's say you're building a store on Rails that you can administer with ActiveAdmin. Assume you have an ActiveAdmin page that lists orders, and you have a filter that allows you to filter by customer. By default, the options in that filter might look something like this:

  • Frye, Adrienne A.

  • Doe, John

  • Adams, Ruth J.

  • Decaro, Felice L.

Ideally, you'd like it to look like this:

  • Adams, Ruth J.

  • Decaro, Felice L.

  • Doe, John

  • Frye, Adrienne A.

One way to do this is to set a default scope on User objects:

class User < ActiveRecord::Base

  ... your current User model code is here ...

  scope :ordered, -> { order('last_name', 'first_name') }
  default_scope { ordered }
end



However, be advised: This approach will cause all queries Rails generates that involve users to add a sort by last name and first name. This will affect query performance, and may cause confusion down the road when records aren't returned in the order you expect.

A better approach would be to extend ActiveAdmin to recognize when models have provided a scope that should be applied when they are rendered in drop-downs.

Try adding this to your ActiveAdmin initializer (i.e. the file where you have "ActiveAdmin.setup"):

ActiveAdmin.setup do |config|

  ... your current initialization code is here ...

  module Formtastic::Inputs::Base::Collections
    ##
    # Overrides {Formtastic::Inputs::Base::Collections.raw_collection} to
    # automatically sort options in filter drop-downs, enhancing the
    # usability of filter drop-downs in ActiveAdmin.
    #
    def raw_collection
      @raw_collection ||=
        (ordered_collection_from_options ||
         ordered_collection_from_association ||
         collection_for_boolean)
    end

    protected
      ##
      # Same as
      # {Formtastic::Inputs::Base::Collections.collection_from_options}
      # except that it automatically sorts the options, if they support
      # it.
      #
      # @return [Array]
      #   The sorted options.
      #
      def ordered_collection_from_options
        collection = collection_from_options

        if collection.respond_to?(:sort)
          collection.sort
        else
          collection
        end
      end

      ##
      # Same as
      # {Formtastic::Inputs::Base::Collections.collection_from_association}
      # except that it automatically applies a +filter_ordered+ scope to
      # the relation, if the relation supports it.
      #
      # @return [ActiveRecord::Relation]
      #   The relation for the collection.
      #
      def ordered_collection_from_association
        relation = collection_from_association

        if relation.klass.respond_to?(:filter_ordered)
          relation.filter_ordered
        else
          relation
        end
      end
  end
end



Now, if you want your users to come out sorted in filters throughout ActiveAdmin, you just need to declare a `filter_ordered` scope instead:

class User < ActiveRecord::Base

  ... your current User model code is here ...

  scope :filter_ordered, -> { order('last_name', 'first_name') }
end



This has the benefit that you don't need to tweak each and every filter through your ActiveAdmin resource pages, AND it has no effect on how users are queried in other contexts (i.e. you didn't have to declare a default scope).

How to Redeem Shopkick Reward Certificates on BestBuy.com
Universal #2
guypaddock
If you are a ShopKick user who recently redeemed "kicks" for a BestBuy loyalty certificate ($2, $5, etc), you might be wondering how you use that certificate on BestBuy.com. The truth is, it isn't very intuitive -- ShopKick was really designed around customers who come into the store to make their purchases, so it isn't integrated into BestBuy's e-commerce flow. As a result, ShopKick tells you to give the loyalty code to the cashier and provides cashier instructions for how to process it, but there isn't any place to put-in that 30 character code on BestBuy.com

The secret is to use the loyalty code like a "RewardZone Certificate". RZ certificates can only be 10 digits, however, so enter just the last 10 digits of the ShopKick loyalty certificate into the RZ certificate box. Then, enter the expiration date from ShopKick into the expiration date box, and the value in the value box. Click "Apply" and POOF! it should be applied.

For example:

ShopKick loyalty code: 020870461800000000003001640664
Expires: 05/26/2012
Value: $2

So, you'd enter:
RZ certificate code: 3001640664
Expiration: 05/26/2012
Value: $2

Quick Tips for running Java EE 6 Tutorials in Eclipse
Universal #2
guypaddock
Hey all,

If you're like me and just getting started with Java EE 6, you're probably trying to follow the Java EE 6 tutorial and finding that some things aren't working.

For starters, the tutorial says to download the example code using the Update Tool for GlassFish, but the example code doesn't show up as an available option. However, following the hint given by a post on Stack Overflow, you can download the examples using Subversion from https://svn.java.net/svn/javaeetutorial~svn.

Second, I found an important tip if you're using Eclipse instead of NetBeans to run tutorials. The first tutorial, "hello1", should be created as a "Dynamic Web Project" with the following settings:

Source folders: src/java
Context root: /hello1
Content directory: web

NOTE: Do not use spaces in the Eclipse project name! If you do, you'll get the following error after entering a name on the first page of the example:


/index.xhtml @19,43 value="#{hello.name}": Target Unreachable, identifier 'hello' resolved to null

The low quality standard of the Oracle GlassFish Installer
Universal #2
guypaddock
So, I just installed GlassFish 3.1.1 on a development machine and I have to say that the experience this time was significantly less intuitive than the last time I installed it.

Let me just start out by saying that I have a lot of admiration and respect for Java. Sun Java. The flavor of Java before Oracle got their greedy hands on it, with their chronic tunnel vision only for catering to large enterprise. I hesitate to install Java SE 7 if it has the same "quality standard" as what I just went through with GlassFish. I especially hesitate to install it knowing that many Java programs might not run correctly on it, or might even corrupt my data.

I also recognize that in an acquisition, it is to be expected that the new parent company's goals will likely not be oriented in the same direction as the company that was acquired. I still think it's a bad idea to burn all of their existing bridges with Apache and Google regarding Java, and screw over the community process, purely because they want to focus on business customers. Students and independent developers of today become the business customers of tomorrow -- a lesson that Sun understood that Oracle is too cold-hearted to understand.

Okay. Enough with my Oracle rant. On to ranting about why GlassFish 3.1.1 seems like the worst install yet:

Sloppy Installer UI


Opening Screen


On the opening screen of the installer, the progress bar isn't even aligned correctly relative to the background:

The progress bar on the first screen of the GlassFish installer is too far left, and looks sloppy.

Really? How much time would it have taken to get that lined up so it doesn't look thrown together?

Installer Screens in General


I noticed that as each screen is displayed, the content area briefly displays HTML code before flashing into the rendered content. I know from Swing development that this can be prevented, if you simply wait for the load event to fire before displaying the control.

JDK Selection screen


The "JDK Selection" screen has several issues. First, if you have only a JRE installed, you will get a message that no "JDK or JRE" was detected. What they really mean to tell you is that no JDK was detected -- a JRE alone won't suffice. Appropriate error message fail.

Second, once you have at least one JDK installed, don't count on using the drop-down of JDKs to select the right one. Due to what I can only assume is sloppy sizing, the drop down has a horizontal scroll bar (!) that covers up at least one of the options in the drop-down. Why is there a horizontal scroll bar? Ignoring that, why is the control not sized appropriately so that the scroll bar doesn't cover up the information?

The drop-down on the &apos;JDK Selection&apos; screen covers up one entire drop-down option with a horizontal scroll bar.

Did this installer get tested on this platform at all? Did the installer get tested at all?

Installation Progress Screen


It doesn't look like any of the installer's windows are appropriately sized, at least not on Windows 7 with Aero enabled. During installation, I had to resize the installer window to give it enough height for the progress bar not to look crowded.

The progress bar on the installation progress screen is cut-off by default.

After resizing:
The progress bar on the installation progress screen is cut-off by default.

In addition, the "billboards" during set-up are clearly being scaled without regard for aspect ratio. Notice how scrunched the text looks.

This is all very sloppy.

Installer Error Handling


The first time I installed GlassFish on this machine, I chose the "Typical" install option. Unfortunately, I didn't realize that I had only the JRE rather than the JDK installed, and apparently GlassFish requires the JDK (which makes sense, since it needs to compile things on request).

The GlassFish installer gives you both a &apos;Typical&apos; and &apos;Custom&apos; install option, but only the &apos;Custom&apos; option gives you appropriate feedback during the installation.

When I used the "Custom" install option, I got a message about this. Instead, with the "Typical" option, the installer proceeded happily along, all the way to the "Configure domain" step, where it failed to configure GlassFish (it got "The system cannot find the file specified"). Worse yet, when I clicked "Finish" after the failed step, I received a message that GlassFish was installed successfully. It even said that it "configured" GlassFish for me. Not quite...

The GlassFish installer always tells you that it configured GlassFish successfully even when it hasn&apos;t.

Uninstaller


My experience with the GlassFish uninstaller was even more ridiculous.

First, if you do manage to install GlassFish, you won't find an entry to uninstall it under "Add/Remove" in the Windows control panel.

In addition, if you install it with the "Typical" option without having a JDK, as I did the first time, you'll find you can't uninstall it -- the uninstaller can't find a JRE to use. To fix this, you'll need to modify the shortcut to the uninstaller to specify the full path to the JRE, and then you'll be able to run it successfully.

I'm still in utter disbelief that on a system where Java was installed to a standard path using the standard Java JRE installer, another installer from the same company is completely incapable of locating Java on the system.

Conclusion


If this type of quality is what we have to expect as the norm with Oracle from here on out, Java is doomed. I will do my part to make sure that the community has other, better options, but with Oracle slamming companies with patent lawsuits when they play outside the Oracle sandbox, I'm not sure whether the community can be saved.

Zimbra, and how (NOT) to break Postfix
Universal #2
guypaddock
Here at RedBottle, we recently started using Zimbra, a most awesome e-mail system. As part of the set-up, we needed to lockdown a feel of our internal mailing lists to prevent outside spammers from sending messages to them. I followed the tutorial on how to restrict Postfix recipients, and learned in the process how to seriously break the ability to send e-mails.

Long story short: don't use comments in the /opt/zimbra/conf/postfix_recipient_restrictions.cf file. Zimbra includes that file inside the value of the smtpd_recipient_restrictions variable of /opt/zimbra/postfix/conf/main.cf. So... if you put comments in the file, those comments become part of the configuration value.

So, for example, my /opt/zimbra/conf/postfix_recipient_restrictions.cf file was like this:

# GAP on 2011-11-16: Adding restriction to outside e-mail for internal RBD distribution lists
check_recipient_access hash:/opt/zimbra/postfix/conf/rbd_protected_recipients

%%contains VAR:zimbraServiceEnabled cbpolicyd, check_policy_service inet:127.0.0.1:10031%%
..remaining file omitted..


Resulting in Zimbra adding the following directive in /opt/zimbra/postfix/conf/main.cf:

smtpd_recipient_restrictions = # GAP on 2011-11-16: Adding restriction to outside e-mail for internal RBD distribution lists, check_recipient_access hash:/opt/zimbra/postfix/conf/rbd_protected_recipients


That, in turn, leads to an error like the following, inside /var/log/zimbra.log:

Nov 17 22:55:45 zimbra-server postfix/smtpd[21240]: fatal: open dictionary: expecting "type:name" form instead of "2011-11-16:"
Nov 17 22:55:46 zimbra-server postfix/master[17417]: warning: process /opt/zimbra/postfix/libexec/smtpd pid 21240 exit status 1
Nov 17 22:55:46 zimbra-server postfix/master[17417]: warning: /opt/zimbra/postfix/libexec/smtpd: bad command startup -- throttling



So... one tiny comment leads to a broken Postfix, which leads to a broken Zimbra because it can't send or receive e-mails (though you can read what you already have in your inbox).

Correct CSipSimple Settings for RingCentral and VirtualPBX
Universal #2
guypaddock
If you've signed-up for cloud PBX phone service from RingCentral or VirtualPBX, and you have an android-based phone running CSipSimple, chances are you've been frustrated by how difficult it is to configure SIP correctly to work with them. Luckily, after spending a few hours last night playing with settings, I believe I have the information you need.


RingCentral
The difficulty with RingCentral is that they use two different usernames -- an "Authorization ID" for the proxy, and a "username" for the actual account -- which is awkward to configure in CSipSimple. Here's how to set it up:
  1. Purchase a new "SIP digital line" on your account from RingCentral, if you haven't already. This won't work unless the digital line is configured for SIP, because only SIP lines have the set-up instructions that include a unique authorization ID that only RingCentral can generate.
  2.  

  3. Pull up the set-up instructions for the SIP digital line. You'll find them under a link that says "Setup instructions", under the name of the line in the "RingCentral DigitalLines" section of your "Account Summary" or "Digital Lines" pages.
  4.  

  5. Create a new account with the "Basic" wizard, and input the following information:
    • Account name: Whatever means something to you; this doesn't affect the connection.
    • User: Enter the "Authorization ID" from the set-up instructions.
    • Server: sip.ringcentral.com
    • Password: Enter the "Password" from the set-up instructions. This is often the same as the "Authorization ID".
    •  

  6. Switch the new account over to the "Expert" wizard. (To do so, press and hold your finger on the account for several seconds, select "Choose wizard", then scroll down and tap "Expert" at the bottom).
  7.  

  8. Open the settings for the new account for modification (i.e. tap on the account in the list).
  9.  

  10. Change the account ID to: "YOUR_DESIRED_CALLER_ID <sip:USER_NAME_FROM_INSTRUCTIONS@sip.ringcentral.com>".The "USER_NAME_FROM_INSTRUCTIONS" is the user name that RingCentral provides you in the instructions (typically the same as the main phone number on your account).
  11. So, for example, if I wanted my caller ID to show up as "(123) 456-7890" and the user name that RingCentral provided me was "18002223333", the account ID would be: "(123) 456-7890 <sip:18002223333@sip.ringcentral.com>".

     

  12. Save settings (i.e. tap the "Save" button").
You should be all set!

VirtualPBX
VirtualPBX has a very picky set-up that only works well with clients from CounterPath. Even after you follow these steps, you'll likely have difficulty making or receiving calls. Their soft switch tends to return code "488 Not Acceptable Here" when calls are initialized, which I believe means that their switch doesn't accept the codecs that CSipSimple is trying to use.

The other problem is that the server name VirtualPBX tells you to use ("virtualpbx.net") is only correct for clients like CounterPath's that actually check DNS records to find out the real host names for SIP. The actual server names, from the SRV DNS records, are "registrar1.virtualpbx.net" or "registrar2.virtualpbx.net".

With all that in mind, if you're feeling adventurous, here's what it takes to get CSipSimple to at least register with VirtualPBX:
  1. Submit a support ticket to Virtual PBX to add a "SIP digital line" to your account, if you haven't already.
  2.  

  3. Wait for the e-mail from VirtualPBX that contains your set-up instructions for the new SIP digital line.
  4.  

  5. Create a new account with the "Basic" wizard, and input the following information:
    • Account name: Whatever means something to you; this doesn't affect the connection.
    • User: Enter the "User Name" from the set-up instructions.
    • Server: registrar1.virtualpbx.net
    • Password: Enter the "Password" from the set-up instructions.
    •  

  6. Switch the new account over to the "Expert" wizard. (To do so, press and hold your finger on the account for several seconds, select "Choose wizard", then scroll down and tap "Expert" at the bottom).
  7.  

  8. Open the settings for the new account for modification (i.e. tap on the account in the list).
  9.  

  10. The account ID will appear as "<USER_NAME_FROM_INSTRUCTIONS@registrar1.virtualpbx.net>". Change the account ID to: "YOUR_DESIRED_CALLER_ID <sip:USER_NAME_FROM_INSTRUCTIONS@virtualpbx.net>".The "USER_NAME_FROM_INSTRUCTIONS" is the user name that VirtualPBX provides you in the instructions.
  11. So, for example, if I wanted my caller ID to show up as "(123) 456-7890" and the user name that VirtualPBX provided me was "2132223333", the account ID would be: "(123) 456-7890 <sip:2132223333@virtualpbx.net>".

     

  12. Save settings (i.e. tap the "Save" button").
CSipSimple should now be able to register with the server, but if you try to make a call it won't go through. That I haven't sorted out just yet.

Outlook Data Files and Ghost Accounts
Universal #2
guypaddock
Recently, I had a problem with Microsoft Outlook 2010 in which a Personal Store (PST) data file was missing. Unfortunately, when I tried removing it from the list of data files, I would get the message:

This data file is associated with a mail account. To remove it use the 'E-mail' tab.


Even though there was no e-mail account associated with the data file. The fix was to open the registry editor, navigate to the following key, export the key to a back-up file (just in case), and then delete the data file from the list of key values:

HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\Outlook\Search\Catalog


Make sure to back-up the registry path before you delete the file from the list!

This fix worked for the data file that belonged to the non-existant, ghost e-mail account. However, I did find out later that if you move a data file and then update the path to the data file under the registry key I mentioned above, Outlook will still look for the file in the old path. Thus, it doesn't appear that Outlook uses to key to find data files, but if the key is missing, Outlook no longer tracks the data file.

Definitely strange behavior, but this fix definitely helped me here.

As always, YMMV.

IE9 Request Queue Strangeness
Universal #2
guypaddock
Hrm, just wanted to post about a curious bug we've run into here at RedBottle with IE 9.0.8112.16421, in case anyone else sees it.

On one of the Drupal sites we maintain, we've noticed that if a page contains several pieces of content that need to be requested after the page loads (for example, song previews for downloadable albums), IE9 frequently gets stuck processing the requests and will no longer function on that site until the browser is navigated elsewhere (i.e. to a completely different site).

Has anyone else seen this issue? It's really bizarre -- it looks like there's an internal queue of requests that, once full, cause the browser not to make any additional requests.

The workaround we were forced to use was to set the page compatibility to IE8. Apparently, the IE9 request engine still needs some work...

Important problem-solving tip when setting-up Apache to use "mod_auth_external" with "pwauth"
Universal #2
guypaddock

The Problem


When setting-up mod_auth_external with pwauth, when it comes time to test your setup you may get to a point where you're staring at the following message in the logs:
Invalid AuthExternal keyword (pwauth)

If so, you're receiving this message for one of two reasons; either:

  1. You forgot to use the "AddExternalAuth" and "SetExternalAuthMethod" directives to define the "pwauth" external authenticator somewhere in the Apache logs that the server will actually read; OR

  2. You defined the "pwauth" external authenticator with the "AddExternalAuth" and "SetExternalAuthMethod" directives, but those definitions are in the global scope of the httpd.conf (or file it includes), rather than inside the <VirtualHost> section from which you are trying to use it.



Case 1 is the trivial case of just forgetting a step as part of installation. Step 2, on the other hand, is counter-intuitive behavior on the part of "mod_auth_external" and is very easy to do by accident.

Consider the following /etc/apache2/modules.d/10_mod_authnz_external.conf file taken from Gentoo Linux:
<IfDefine AUTHNZ_EXTERNAL>
LoadModule authnz_external_module modules/mod_authnz_external.so

# provided by net-www/pwauth
AddExternalAuth pwauth /usr/sbin/pwauth
SetExternalAuthMethod pwauth pipe

# For external group check (provided by net-www/pwauth)
AddExternalGroup unixgroup /usr/sbin/unixgroup
SetExternalGroupMethod unixgroup environment
...
</IfDefine>


At least in the Gentoo distro, Apache includes this file in httpd.conf, as follows:
...
Include /etc/apache2/modules.d/*.conf
...


This essentially means that the "pwauth" external authenticator and "unixgroup" external group authenticator are defined in the "global" scope of the configuration file, rather than being associated with a particular virtual host. One would naturally assume, then, that these two would be available from within any <VirtualHost> section, but that turns out not to be the case.

For example, consider the situation below:
<VirtualHost *:80>
    ...
    <Directory /var/www/vhosts/mydomain.com/cgi-bin>
        ...
        Order Deny,Allow

        AuthType Basic
        AuthName "Red Bottle Design - Developers"
        AuthBasicProvider external
        AuthExternal pwauth

        GroupExternal unixgroup
        Require group developers
        ...
    </Directory>
</VirtualHost>


In this scenario, the bolded directives above would be the cause of the "Invalid AuthExternal keyword" and "Invalid GroupExternal keyword" errors.

The Solution


There are two solutions to this conundrum; either:

  1. Move the authentication directives (AuthType, AuthName, AuthBasicProvider, etc). into an .htaccess file in the top-level folder of the website. Oddly enough, the .htaccess file does have access to these authentication providers defined in global scope; OR

  2. Follow the recommendation from the "Communication" section of the article in the Gentoo Wiki about setting this up and put authenticator definitions in a separate auth.include file that you can include from multiple virtual hosts.



I went with option 2, since I don't like the idea of security on some sites going away as easily as just losing an .htaccess file. Personally, though, I feel this is some counter-intuitive behavior that should be addressed, because global definitions should still be available in <VirtualHost> sections.

Tips and Tricks for C: Bashing Sensitive Command-line Arguments Like Mysqldump
Universal #2
guypaddock
While working at Red Bottle, I recently learned that the mysqldump command, which is used to dump a MySQL database to a text file, will intelligently hide passwords that it is passed on the command-line.

Don't believe me? Try it. Run mysqldump with appropriate arguments, including a password argument in the format --password=<YOUR PASSWORD> or -p<YOUR PASSWORD>, and then look at the output of ps aux. You should see that the mysqldump command line looks something like this:

mysqldump -h localhost -u username -px_xxxxxxxxxxxxx the_database

I didn't add in the xxxxxxxxxxxxx part in the above example output – the mysqldump process actually bashed that argument after processing it.

How?

Well, as we all know, the standard declaration for the C main function goes like this:
int main( int argc, const char* argv[] )
{
  ... your main code ...
}

Usually, you declare the argv[] parameter array to be const to prevent yourself from accidentally bashing parameters. But, as it turns out, you can omit const, and the compiler will still be happy with you.

This is essentially what mysqldump does – if you grab a copy of any recent version of the mysqldump source code, and look in the get_one_option() function (around line 570 in the copy I link to), you'll see code like this:
if (argument)
{
  char *start=argument;
  my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
  opt_password=my_strdup(argument,MYF(MY_FAE));
  while (*argument) *argument++= 'x';   /* Destroy argument */
  if (*start)
    start[1]=0;  /* Cut length of argument */
  tty_password= 0;
}

else
  tty_password=1;
break;

It loops through, replacing password characters with "x", and attempting to shorten the length so that malicious users on the same system don't know exactly how long the real password is.

Applying this knowledge, we can do something like this:
int main(int argc, char* argv[])
{
  if (argc > 1)
  {
    char *start = argv[1];
    
    /* ...you would store the password somewhere internal to the application here... */

    // Bash the password
    while (*argv[1]) *argv[1]++= 'x';
    
    if (*start)
      start[1]=0;
  }
  
  // Give us time to look at the process list
  sleep(10);
}

If you compile and run the above program with a command-line argument, you will see that the argument is replaced with "x"s in the output of "ps aux", just like with mysqldump. Neat, huh?

A word of caution: The documentation for mysqldump does say that passing the password on the command-line is still insecure, and I would agree. I am sure that mysqldump only uses the practice described above for users who insist on passing the password in this fashion; in your own applications, I would provide users with a safe alternative way to specify passwords, and rely only on the practice of bashing passwords on the command-line as a last resort.

Consider that, even with the above code, there is a period of time between the program starting and the end of the while loop, during which the password has not been bashed. If your own application does checks and additional logic before processing command-line arguments, this window of time is even longer.

To see a demonstration of what I mean, add a sleep call before the code that bashes the argument, as follows:
int main(int argc, char* argv[])
{
  // Simulate application processing before arguments are bashed.
  sleep(5);

  if (argc > 1)
  {
    char *start = argv[1];
    
    while (*argv[1]) *argv[1]++= 'x';
    
    if (*start)
      start[1]=0;
  }
  
  // Give us time to look at the process list
  sleep(10);
}

If you compile and run the above program with an argument, you'll find that for the first five seconds the program is running, the argument you passed is available raw in the process list output of ps aux!

So, the moral of the story is that bashing sensitive command-line arguments is a useful tool as part of a larger set of security practices you can adopt in your application to try and safeguard information from users who are not security-conscious, but it is foolhardy to rely on it as your only safeguard.

?

Log in