Showing posts with label How To. Show all posts
Showing posts with label How To. Show all posts

Monday, November 8, 2010

Offline installation of Anrdoid SDK (Platforms and addons)

I installed Android SDK the other day to explore the apps platform for 2.1 (now that I have an Android phone!)…

Things you need:

A. SDK Starter package which just needs to be unzipped into a location (no installation as such):
PlatformPackageSizeMD5 Checksum
Windowsandroid-sdk_r07-windows.zip23669664 bytes69c40c2d2e408b623156934f9ae574f0
Mac OS X (intel)android-sdk_r07-mac_x86.zip19229546 bytes0f330ed3ebb36786faf6dc72b8acf819
Linux (i386)android-sdk_r07-linux_x86.tgz17114517 bytese10c75da3d1aa147ddd4a5c58bfc3646


B. Platform package which is one or more of the various android versions for which you will be coding. Eg: 2.2, 2.1, 1.6, 1.5, etc.

This has to be selected and downloaded from within the Android SDK.


But Google was forcing me to download the platform package only through the SDK. Why can’t I have a set of zips I can reuse on my laptop, desltop1, desktop2 as needed instead of having to download the Android platform repeatedly from the net for each machine?


The answer was simple after a little investigation but apparently undocumented. See below steps for full offline installation:

1) First you need to download repository.xml file. To find out the download link for this file, launch Android AVD Manager (after unzipping the sdk, manually from %AndroidSDKDir%\tools\Android.bat or from the Eclipse plugin). Here, when you select available Packages, you will see the default target: http://dl.google.com/android/repository/repository.xml (maybe slightly different for you). Download this respository.xml file from the net (and close the AVD manager).

2) Open the repository.xml file and search for <sdk:platform>. You will see around 5 entries for each Android platform/version.

Identify the version you want and look for the platform filename inside the <sdk:url> tag. In my case, I wanted the 2.1 platform:

<sdk:platform>
<sdk:version>2.1</sdk:version>
<sdk:api-level>7</sdk:api-level>
<sdk:codename/>
<sdk:revision>02</sdk:revision>
<sdk:min-tools-rev>6</sdk:min-tools-rev>
<sdk:description>Android SDK Platform 2.1_r2</sdk:description>
<sdk:desc-url>http://developer.android.com/sdk/</sdk:desc-url>
<sdk:archives>
<sdk:archive os="linux" arch="any">
<sdk:size>72356359</sdk:size>
<sdk:checksum type="sha1">a89d32ddf9d8629f15e682bdf220a88ca2392349</sdk:checksum>
<sdk:url>android-2.1_r02-linux.zip</sdk:url>
</sdk:archive>
<sdk:archive os="macosx" arch="any">
<sdk:size>71054909</sdk:size>
<sdk:checksum type="sha1">8492e2f0b61819c4ca2e16601fc3260b341a3f06</sdk:checksum>
<sdk:url>android-2.1_r02-macosx.zip</sdk:url>
</sdk:archive>
<sdk:archive os="windows" arch="any">
<sdk:size>72950641</sdk:size>
<sdk:checksum type="sha1">00cfb0bbbf24fc56c493990186deb0bfd44630e5</sdk:checksum>
<sdk:url>android-2.1_r02-windows.zip</sdk:url>
</sdk:archive>
</sdk:archives>
</sdk:platform>



3) In the url obtained from step 1 (http://dl.google.com/android/repository/repository.xml), replace repository.xml with the identified filename to get the actual url of the platform file. So in this example, the url would be: http://dl.google.com/android/repository/android-2.1_r02-windows.zip

Download this file (by typing into your browser url for eg).

4) Once the file is downloaded, extract this file into the <Androidsdk>\platforms directory. So you would end up with a new directory here as %AndroidSDKDir%\platforms\android-2.1_r02-windows.

That’s it!

If you now open the AVD manager again and click on Installed Packages, the extracted platform will show up as “SDK Platform Android a.b-update c, API d, revision e”


Use similar steps to download any Addons like Google APIs, but extract the Add-ons into %AndroidSDKDir%\add-ons directory. Just make sure that before you install the Addons, you have the corresponding platform already unzipped into the platforms directory.


To summarise, now I don’t need a net connection when to install the full android SDK – I just have to keep the following files handy:

· android-sdk_r07-windows.zip (unzip into a location where you want to install Android SDK, %AndroidSDKDir%)

· android-2.1_r02-windows.zip (unzip into %AndroidSDKDir%\platforms)

· google_apis-7_r01.zip (unzip into %AndroidSDKDir%\add-ons)

· ADT-0.9.9.zip (optional but useful Eclipse plugin – see here how to install this offline into Eclipse)



Happy droiding!

Monday, September 20, 2010

UK Postcode regular expression

A friend of mine asked for a regular expression for UK Post codes… got so many confusing results on the net that I decided to make it myself.

First had to find the rules for UK Postcode. A quick search got me a UK government site, (old site was: http://www.cabinetoffice.gov.uk/govtalk/schemasstandards/e-gif/datastandards/address/postcode.aspx as of October 2009. Updated to new site) http://interim.cabinetoffice.gov.uk/govtalk/schemasstandards/e-gif/datastandards/address/postcode.aspx, as of July 2011, which shows the rules as follows:

Permitted Format

Example Postcode

AN NAA

M1 1AA

ANN NAA

M60 1NW

AAN NAA

CR2 6XH

AANN NAA

DN55 1PT

ANA NAA

W1A 1HQ

AANA NAA

EC1A 1BB

Also

* The letters Q, V and X are not used in the first position.

* The letters I, J and Z are not used in the second position.

* The only letters to appear in the third position are A, B, C, D, E, F, G, H, J, K, S, T, U and W.

* The only letters to appear in the fourth position are A, B, E, H, M, N, P, R, V, W, X and Y.

* The second half of the Postcode is always consistent numeric, alpha, alpha format and the letters C, I, K, M, O and V are never used.

* GIR 0AA is a Postcode that was issued historically and does not confirm to current rules on valid Postcode formats, It is however, still in use.

Was able to come up with this basic Regular expression that does UK Postcode validation:

^([A-PR-UWYZ](([0-9](([0-9]|[A-HJKSTUW])?)?)|([A-HK-Y][0-9]([0-9]|[ABEHMNPRVWXY])?)) [0-9][ABD-HJLNP-UW-Z]{2})|GIR 0AA$

This will validate 100% as per the assumed rules above.
Note however that it is certainly not optimized… I couldn't find any online regular expression optimizer and I’ll have to become a regex expert to do anything about it. Maybe I can take automatic regex optmizer thing as a mini-project. But for now, the unoptimized version will have to do...

Here is the regular expression in action inside Java code:

public static void validate(String code) {

String regexp="^([A-PR-UWYZ](([0-9](([0-9]|[A-HJKSTUW])?)?)|([A-HK-Y][0-9]([0-9]|[ABEHMNPRVWXY])?)) [0-9][ABD-HJLNP-UW-Z]{2})|GIR 0AA$";

Pattern pattern = Pattern.compile(regexp);

Matcher matcher = pattern.matcher(code.toUpperCase());

if (matcher.matches()) {

System.out.println("This is a valid UK Postcode.");

} else {

System.out.println("This is not a valid UK Postcode.");

}

}

In a real life scenario, you may need to convert the received code into upper case before calling validate to be safe. Or better yet, have upper and lower case validation inside the regular expression itself! Plus of course the optimization…

Wednesday, May 12, 2010

Support for NTLMv2 with Apache HttpClient using JCIFS

Here, I'll explain how to get NTLMv2 support in HttpClient 3.x using JCIFS by using 1 addditional class and inserting 1 new line into your existing calls to HttpClient.
Of course you can use JCIFS NTLM authentication directly in Java even if you don't have Apache HttpClient - I'm not looking at that but you can refer to this guide on JCIFS home page.

HttpClient
Apache's HttpClient provides some useful encapsulation for fetching/posting data over HTTP through Java code. The common version is HttpClient 3.x whereas the latest version is HttpClient 4.x.

NTLM
One of HttpClient's advantages is that it has built in support to manage communications over an NTLM proxy.
NTLM is a very closely guarded Proxy protocol used by Microsoft but still popularly used.

JCIFS
Unfortunately, HttpClient does not have built in support for NTLM v2. The good news is, it allows you to integrate NTLMv2 support through another library called JCIFS.
JCIFS is an Open Source  client library that implements the CIFS/SMB networking protocol in 100% Java. See more details/download from here. But since JCIFS started NTLMv2 support only from 1.3.0, make sure you have the latest JCIFS jar (I tested with JCIFS 1.3.14).

JCIFS in HttpClient
Thankfully, HttpClient 4.x home site has a page containing unofficial steps for integrating JCIFS into HTTPClient. However, these steps will only work for 4.x and not for for 3.x. This is because HttpClient 4.x is not backward compatible with 3.x. There are major changes like package structures, new Engines instead of States, etc.

Since I was using HttpClient 3.x, I started thinking of upgrading to 4.x – but it was obvious upgrading to 4.x from 3.x was a nightmare just to get NTLMv2 support.

Thankfully, it was just a matter of understanding HttpClient 3.x internal calls from the source. I was able to create 1 simple class that will do the integration in 1 smooth move.

Steps and source-code
1)      I created a new class, JCIFS_NTLMScheme.java that would be used in place of HTTPClient's NTLMScheme.
This new class simply makes calls to JCIFS internally to generate NTLMv2's Type1, 2 and 3 messages- just reimplemented the methods with slight logic changes to generate the messages:
package org.xyz;

import java.io.IOException;

import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.NTCredentials;
import org.apache.commons.httpclient.auth.AuthChallengeParser;
import org.apache.commons.httpclient.auth.AuthScheme;
import org.apache.commons.httpclient.auth.AuthenticationException;
import org.apache.commons.httpclient.auth.InvalidCredentialsException;
import org.apache.commons.httpclient.auth.MalformedChallengeException;
import org.sac.crosspather.common.util.AppLogger;
import org.sac.crosspather.common.util.HTTPHelper;

/**
 * This is a reimplementation of HTTPClient 3.x's
 * org.apache.commons.httpclient.auth.NTLMScheme.<BR/>
 * It will basically use JCIFS (v1.3.15) in order to provide added support for
 * NTLMv2 (instead of trying to create its own Type, 2 and 3 messages). <BR/>
 * This class has to be registered manually with HTTPClient before setting
 * NTCredentials: AuthPolicy.registerAuthScheme(AuthPolicy.NTLM,
 * JCIFS_NTLMScheme.class); <BR/>
 * Will <B>not</B> work with HttpClient 4.x which requires AuthEngine to be overriden instead of AuthScheme.
 *
 * @author Sachin M
 */
public class JCIFS_NTLMScheme implements AuthScheme {

       private static AppLogger logger = new AppLogger(HTTPHelper.class.getName());

       /** NTLM challenge string. */
       private String ntlmchallenge = null;

       private static final int UNINITIATED = 0;
       private static final int INITIATED = 1;
       private static final int TYPE1_MSG_GENERATED = 2;
       private static final int TYPE2_MSG_RECEIVED = 3;
       private static final int TYPE3_MSG_GENERATED = 4;
       private static final int FAILED = Integer.MAX_VALUE;

       /** Authentication process state */
       private int state;

       public JCIFS_NTLMScheme() throws AuthenticationException {
              // Check if JCIFS is present. If not present, do not proceed.
              try {
                     Class.forName("jcifs.ntlmssp.NtlmMessage",false,this.getClass().getClassLoader());
              } catch (ClassNotFoundException e) {
                     throw new AuthenticationException("Unable to proceed as JCIFS library is not found.");
              }
       }
      
       public String authenticate(Credentials credentials, HttpMethod method)
                     throws AuthenticationException {
              logger.doLog(AppLogger.FINEST,
                           "Enter JCIFS_NTLMScheme.authenticate(Credentials, HttpMethod)",
                           null);

              if (this.state == UNINITIATED) {
                     throw new IllegalStateException(
                                  "NTLM authentication process has not been initiated");
              }

              NTCredentials ntcredentials = null;
              try {
                     ntcredentials = (NTCredentials) credentials;
              } catch (ClassCastException e) {
                     throw new InvalidCredentialsException(
                                  "Credentials cannot be used for NTLM authentication: "
                                                + credentials.getClass().getName());
              }
             
              NTLM ntlm = new NTLM();
              ntlm.setCredentialCharset(method.getParams().getCredentialCharset());
              String response = null;
              if (this.state == INITIATED || this.state == FAILED) {
                     response = ntlm.generateType1Msg(ntcredentials.getHost(),
                                  ntcredentials.getDomain());
                     this.state = TYPE1_MSG_GENERATED;
              } else {
                     response = ntlm.generateType3Msg(ntcredentials.getUserName(),
                                  ntcredentials.getPassword(), ntcredentials.getHost(),
                                  ntcredentials.getDomain(), this.ntlmchallenge);
                     this.state = TYPE3_MSG_GENERATED;
              }
              return "NTLM " + response;

       }

       public String authenticate(Credentials credentials, String method,
                     String uri) throws AuthenticationException {
              throw new RuntimeException(
                           "Not implemented as it is deprecated anyway in Httpclient 3.x");
       }

       public String getID() {
              throw new RuntimeException(
                           "Not implemented as it is deprecated anyway in Httpclient 3.x");
       }

       /**
        * Returns the authentication parameter with the given name, if available.
        *
        * <p>
        * There are no valid parameters for NTLM authentication so this method
        * always returns <tt>null</tt>.
        * </p>
        *
        * @param name
        *            The name of the parameter to be returned
        *
        * @return the parameter with the given name
        */
       public String getParameter(String name) {
              if (name == null) {
                     throw new IllegalArgumentException("Parameter name may not be null");
              }
              return null;
       }

       /**
        * The concept of an authentication realm is not supported by the NTLM
        * authentication scheme. Always returns <code>null</code>.
        *
        * @return <code>null</code>
        */
       public String getRealm() {
              return null;
       }

       /**
        * Returns textual designation of the NTLM authentication scheme.
        *
        * @return <code>ntlm</code>
        */
       public String getSchemeName() {
              return "ntlm";
       }

       /**
        * Tests if the NTLM authentication process has been completed.
        *
        * @return <tt>true</tt> if Basic authorization has been processed,
        *         <tt>false</tt> otherwise.
        *
        * @since 3.0
        */
       public boolean isComplete() {
              return this.state == TYPE3_MSG_GENERATED || this.state == FAILED;
       }

       /**
        * Returns <tt>true</tt>. NTLM authentication scheme is connection based.
        *
        * @return <tt>true</tt>.
        *
        * @since 3.0
        */
       public boolean isConnectionBased() {
              return true;
       }

       /**
        * Processes the NTLM challenge.
        *
        * @param challenge
        *            the challenge string
        *
        * @throws MalformedChallengeException
        *             is thrown if the authentication challenge is malformed
        *
        * @since 3.0
        */
       public void processChallenge(final String challenge)
                     throws MalformedChallengeException {
              String s = AuthChallengeParser.extractScheme(challenge);
              if (!s.equalsIgnoreCase(getSchemeName())) {
                     throw new MalformedChallengeException("Invalid NTLM challenge: "
                                  + challenge);
              }
              int i = challenge.indexOf(' ');
              if (i != -1) {
                     s = challenge.substring(i, challenge.length());
                     this.ntlmchallenge = s.trim();
                     this.state = TYPE2_MSG_RECEIVED;
              } else {
                     this.ntlmchallenge = "";
                     if (this.state == UNINITIATED) {
                           this.state = INITIATED;
                     } else {
                           this.state = FAILED;
                     }
              }
       }

       private class NTLM {
           /** Character encoding */
           public static final String DEFAULT_CHARSET = "ASCII";
          
           /**
               * The character was used by 3.x's NTLM to encode the username and
               * password. Apparently, this is not needed in when passing username,
               * password from NTCredentials to the JCIFS library
               */
           private String credentialCharset = DEFAULT_CHARSET;
          
              void setCredentialCharset(String credentialCharset) {
                     this.credentialCharset = credentialCharset;
              }

              private String generateType1Msg(String host, String domain) {
                     jcifs.ntlmssp.Type1Message t1m = new jcifs.ntlmssp.Type1Message(jcifs.ntlmssp.Type1Message.getDefaultFlags(),
                                  domain, host);
                     return jcifs.util.Base64.encode(t1m.toByteArray());
              }

              private String generateType3Msg(String username, String password, String host,
                           String domain, String challenge) {
                     jcifs.ntlmssp.Type2Message t2m;
                     try {
                           t2m = new jcifs.ntlmssp.Type2Message(jcifs.util.Base64.decode(challenge));
                     } catch (IOException e) {
                           throw new RuntimeException("Invalid Type2 message", e);
                     }

                     jcifs.ntlmssp.Type3Message t3m = new jcifs.ntlmssp.Type3Message(t2m, password, domain,
                                  username, host, 0);
                     return jcifs.util.Base64.encode(t3m.toByteArray());
              }
       }
}

2)      Then it was Register the new JCIFS_NTLMScheme class as the replacement for NTLMScheme by using the following command:
AuthPolicy.registerAuthScheme(AuthPolicy.NTLM, org.xyz.JCIFS_NTLMScheme.class);
 (AuthPolicy is a class in HTTPClient 3.x jar)

That's it! Use your HTTPClient as normal but just make sure you call the above register command before you create and bind the HttpClient's NTCredentials class
 
Superblog Directory