Tuesday, February 17, 2015

Enterprise Management: User-Agent Switcher for Chrome

When I first wrote the User-Agent Switcher for Chrome, I imagined that it would be useful for administrators who wanted their users to use Chrome, but hack around legacy web apps that expected and required ancient browser versions.  Anyone using the steaming turd that is Outlook Web Access knows what I'm talking about.

However, Chrome didn't offer a way to manage extensions' settings -- only policies for managing itself...until recently.  With policy for extensions, Chrome now allows administrators to send policy settings directly to extensions -- not only can you deploy this extension, you could also deploy all the user-agents and permanent spoofs.

Setting policy for extensions is similar to setting policy for other applications on the target OS: the registry on Windows, a protected directory on Linux, Workgroup Manager on Mac, etc.  Chrome looks for these policies and then applies them to the extension (but only if they are crafted correctly -- more on that later.)

In version ~1.0.38, I added support for policy in the extension: I added the ability to set the user-agents, permanent spoofs, and a few of the other settings...and I hope to add more controls in the future.

To take advantage of this, you'll need to follow the steps below.  Unfortunately, every OS has its own format and own way of handling admin policies, so you may have to follow several of these to get coverage on your entire fleet.

Side note: I often found that any misspelling, or slightly-off structure of JSON or XML would cause policy to silently fail (*cough* broken user journey *cough*), so be sure your structure is correct.  Some debugging tips are at the very end of this post.

What Policies Are Supported

I added support for the most typical things an admin would change -- if you peek down at some of the sample policy files below, the structure should make some sense.  The policies currently supported include:
  • UserAgents -- a list of user-agent strings available for the user.  This is a List of Dictionaries/Hashes that contain the following values:
    • title [string] - the name of the user-agent ("Chrome 41")
    • ua_string [string] - the value of the user-agent string
    • vendor [string] - the value of the "navigator.vendor" field
    • badge [string] - the couple of letters that show up over the icon when spoofing
    • append [boolean]- whether the ua_string value should be appended to Chrome's user-agent (false means replace it)
  • PermanentSpoofs -- a list of permanent spoofs.  This is a List of Dictionaries/Hashes that contain the following values:
    • domain - [string] the domain regular expression to match.
    • user_agent - [dictionary] - this is a full UserAgent object (see above).  This is the user-agent to use with the permanent spoof.
  • EditRights -- several one-off settings for defining what users can edit.  This is a Dictionary.  Regardless of what you set here, users cannot modify user-agents or spoofs provided via policy.
    • user_agents [boolean] - whether the user can edit/add/delete user_agent strings.
    • permanent_spoofs [boolean] - whether the user can edit/add/delete permanent spoofs.
  • Other Settings -- more one-off settings representing the "Other Settings" section in the options screen.  This is a Dictionary of values.
    • hotlist_enabled [boolean] - Whether the user can switch the spoofed user-agent on the fly.
    • spoof_override [boolean] - Whether the on-the-fly spoof user-agent overrides permanent spoofs.
    • spoof_per_tab [boolean] - Whether the on-the-fly spoof applies only to the current tab.

Setup on Chrome OS / Google-managed Chrome

The Admin console has a place to manage extensions' settings (more info here.)  When you find the part of the admin console for setting extensions' policies, you can use JSON of this form:

{ "UserAgents": { "Value": [ {"title": "1", "ua_string": "ua_1", "vendor": "v_1", "badge": "A1", "append" : false}, {"title": "2", "ua_string": "ua_2", "vendor": "v_2", "badge": "A2", "append" : false}, {"title": "3", "ua_string": "ua_3", "vendor": "v_3", "badge": "A3", "append" : true} ] }, "PermanentSpoofs": { "Value": [ {"domain" : "foo.com", "user_agent": {"title": "4", "ua_string": "ua_4", "vendor": "v_4", "badge": "A4", "append" : false}}, {"domain" : "bar.com", "user_agent": {"title": "5", "ua_string": "ua_5", "vendor": "v_5", "badge": "A5", "append" : true}} ] }, "EditRights": { "Value": [ {"user_agents" : false, "permanent_spoofs": false} ] }, "OtherSettings": { "Value": { "hotlist_enabled" : false, "spoof_override": true, "spoof_per_tab": false } } }


Setup on Windows

Full disclosure: I haven't tested this at all, since I don't have any Windows machines to work on anymore, but I *think* this is the right structure.  Feedback is greatly appreciated on whether this works or not.


[HKEY_LOCAL_MACHINE\Software\Policies\Google\Chrome\3rdparty\extensions\jhefaickifmkaeoijafmdniimnjfohef\policy\UserAgents\1
"title"="Test"
"ua_string"="Test UA 1"
"vendor"="Testing"
"badge"="aaa"
"append"=false

[HKEY_LOCAL_MACHINE\Software\Policies\Google\Chrome\3rdparty\extensions\jhefaickifmkaeoijafmdniimnjfohef\policy\PermanentSpoofs\1
"domain"="foo.com"

[HKEY_LOCAL_MACHINE\Software\Policies\Google\Chrome\3rdparty\extensions\jhefaickifmkaeoijafmdniimnjfohef\policy\PermanentSpoofs\1\user_agent
"title"="Test 2"
"ua_string"="Test UA 2"
"vendor"="Testing 2"
"badge"="bbb"
"append"=true

[HKEY_LOCAL_MACHINE\Software\Policies\Google\Chrome\3rdparty\extensions\jhefaickifmkaeoijafmdniimnjfohef\policy\EditRights
"user_agents"=false
"permanent_spoofs"=false

[HKEY_LOCAL_MACHINE\Software\Policies\Google\Chrome\3rdparty\extensions\jhefaickifmkaeoijafmdniimnjfohef\policy\EditRights
"hotlist_enabled"=false
"spoof_override"=false
"spoof_per_tab"=false

Again, I'm not totally sure this is exactly right since I don't have a good way to test it, but please post in the comments if it does.


Setup on Mac

Mac devices use "plist" (policy list?) files to distribute settings -- these are glorified xml text files.  The format for this extension looks like this:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>com.google.Chrome.extensions.jhefaickifmkaeoijafmdniimnjfohef</key>
  <dict>
    <key>UserAgents</key>
    <dict>
      <key>state</key>
      <string>always</string>
      <key>value</key>
      <array>
        <dict>
          <key>title</key>
          <string>mac_plist_1</string>
          <key>ua_string</key>
          <string>mac plist 1</string>
          <key>vendor</key>
          <string>mac vendor 1</string>
          <key>badge</key>
          <string>aaa</string>
          <key>append</key>
          <false/>
        </dict>
        <dict>
          <key>title</key>
          <string>mac_plist_2</string>
          <key>ua_string</key>
          <string>mac plist 2</string>
          <key>vendor</key>
          <string>mac vendor 2</string>
          <key>badge</key>
          <string>bbb</string>
          <key>append</key>
          <true/>
        </dict>
      </array>
    </dict>
    <key>PermanentSpoofs</key>
    <dict>
      <key>state</key>
      <string>always</string>
      <key>value</key>
      <array>
        <dict>
          <key>domain</key>
          <string>www.foo1.com</string>
          <key>user_agent</key>
          <dict>
            <key>title</key>
            <string>mac_plist_3</string>
            <key>ua_string</key>
            <string>mac plist 3</string>
            <key>vendor</key>
            <string>mac vendor 3</string>
            <key>badge</key>
            <string>ccc</string>
            <key>append</key>
            <true/>
          </dict>
        </dict>
        <dict>
          <key>domain</key>
          <string>whatsmyuseragent.com</string>
          <key>user_agent</key>
          <dict>
            <key>title</key>
            <string>mac_plist_4</string>
            <key>ua_string</key>
            <string>mac plist 4</string>
            <key>vendor</key>
            <string>mac vendor 4</string>
            <key>badge</key>
            <string>ddd</string>
            <key>append</key>
            <false/>
          </dict>
        </dict>
      </array>
    </dict>
    <key>EditRights</key>
    <dict>
      <key>state</key>
      <string>always</string>
      <key>value</key>
      <dict>
        <key>user_agents</key>
        <true/>
        <key>permanent_spoofs</key>
        <true/>
      </dict>
    </dict>
    <key>OtherSettings</key>
    <dict>
      <key>state</key>
      <string>always</string>
      <key>value</key>
      <dict>
        <key>hotlist_enabled</key>
        <true/>
        <key>spoof_override</key>
        <true/>
        <key>spoof_per_tab</key>
        <false/>
        <key>send_errors</key>
        <false/>
      </dict>
    </dict>
  </dict>
</dict>
</plist>



Take this content, save it in a file with a name like "abc.plist".  You'll obviously want to update this to adjust to the settings you want -- these are just my test settings.  Mac administrators can deploy this file via Workgroup Manager, with some guidance on how to do this on the Chromium site.


Setup on Linux

I've never tested this on Linux myself, but I surmise that if you use JSON of the same structure as the Chrome OS policy, and put it in a JSON file in the right location (some basic instructions here.)


Why Isn't It Working / Debugging 

In my development and testing, I found it very common for the policies I was trying to set to not appear at all.  Here's a couple of tricks I used to debug issues with getting policies picked up:


  • http://about:policy is a huge help: it shows if the browser is picking up policies for extensions.  If it's not appearing here, it's not getting to the browser.
  • Any misspelling, missing comma (JSON), using true instead of , etc. will make the OS and the browser just ignore the policy.  If the policy isn't appearing in about:policy, or in the OS's policy viewer, there is a good chance the structure is off.
  • When encountering #2, I found it helpful to get just one *very* basic policy working, then build up the other necessary policies one at a time.


Final Thoughts


I'm hoping that some admins out there who are trying to hack around some legacy systems' problems will find this useful.  Not every setting has a corresponding policy, so there's more work for me to do.  I also need to test on more systems, but I think this should work.

Feedback is greatly appreciated -- feel free to leave it here, or on my G+ page.

6 comments:

  1. ChromeOS on Chromebook 05/10/2015

    Hello Glenn - just a note to say I really appreciate the User Agent Spoofer - I used to use it to spoof OWA for Outlook, so I could get the full version, not just the lite.

    Then recently Citrix Receiver began to work, (including opening ica files) so I tried that on my Chromebook... and nothing happened. Then I remembered Chorme UA Spoofer, set the User Agent to OWA and bingo, there it was.

    All I don't have now is printing from the Citrix Desktop linked to Cloud Print. I have to evaluate all this for a little while but I can't ask them (upstairs) because they don't consider Chromebooks to be real computers and I might get into trouble!! Chromebook is the ultimate dumb client, with optional intelligence via extensions, only an idiot couldn't see that.

    I lost one of mine recently and hastily reset the list of authorised devices, requiring dual authentication for them all. Sure enough, a few days later there comes a text, at 3 in the morning, from a low life trying to log in to my chromebook :( I am working on an extension to deliver 60,000 Volts via the testicles of any would be hacker of my chrome devices so they'd better watch out (Grrr)!

    Many thanks
    My proper name is John Crosskey :)

    ReplyDelete
    Replies
    1. Glad it can be of use to you John! Having had the enviable job of asking websites to fix their user-agent detection when Chrome launched, I was shocked at how many worked just fine when spoofed -- glad to hear that has helped you.

      If you are managing your devices via the Chrome management console, I believe there are options for lost/stolen devices. I'm not up to date on what they let you do (other than unenroll them?) Either way, I think your thief will think twice about ever taking a chromebook again :)

      Cheers,
      Glenn

      Delete
  2. This comment has been removed by the author.

    ReplyDelete
  3. Hey Glenn, this sounds really good.

    I try to figure it out on Linux clients but it is tricky.

    If i just copy the chrome OS JSON to /etc/opt/chrome/policies/managed/chrome_managed_policy.json i only get “Status: Unknown policy”. Under http://about:policy

    If i click “Show policies with no value set” and scroll all the way down, i can see another passage named User-Agent Switcher for Chrome ID: djflhoibgkdhkhhcedjiklpkjnoahfmg with the Policy names from your JSON Status: Not set.

    Do you have an idea or a tip how to set a managed policy in the User-Agent Switcher Policy passage?

    Here are tow screen shots for better understanding:
    http://www.bilder-upload.eu/show.php?file=849b40-1449670877.png
    http://www.bilder-upload.eu/show.php?file=3ac3cc-1449670743.png

    ReplyDelete
  4. with the big help of the chromium community:
    here is a json for linux that force install User-Agent Switcher and set the example values from this page:
    {
    "ExtensionInstallForcelist": [
    "djflhoibgkdhkhhcedjiklpkjnoahfmg;https://clients2.google.com/service/update2/crx"
    ],
    "3rdparty" : {
    "extensions" : {
    "djflhoibgkdhkhhcedjiklpkjnoahfmg": {
    "UserAgents": [
    {"title": "1", "ua_string": "ua_1", "vendor": "v_1", "badge": "A1", "append" : false},
    {"title": "2", "ua_string": "ua_2", "vendor": "v_2", "badge": "A2", "append" : false},
    {"title": "3", "ua_string": "ua_3", "vendor": "v_3", "badge": "A3", "append" : true}
    ],
    "PermanentSpoofs": [
    {"domain" : "foo.com", "user_agent": {"title": "4", "ua_string": "ua_4", "vendor": "v_4", "badge": "A4", "append" : false}},
    {"domain" : "bar.com", "user_agent": {"title": "5", "ua_string": "ua_5", "vendor": "v_5", "badge": "A5", "append" : true}}
    ],
    "EditRights": {
    "user_agents" : false, "permanent_spoofs": false
    },
    "OtherSettings": {
    "hotlist_enabled" : false, "spoof_override": true, "spoof_per_tab": false, "send_errors": false
    }
    }
    }
    }
    }

    ReplyDelete
  5. finally im an iphone developer!!!!!! but im worried that my apps will be pirated. is there anyway that i can protect my apps?chrome plugin development

    ReplyDelete