Thursday, April 17, 2014

Eclipse ADT Update

Quick info:


Eclipse ADT plugin asks for an update from time to time. If you get weird errors for ADT plugin update, i got some workaround for you.

In Eclipse, Go to Help menu:
Help > Install New Software
Then Add new entry or choose the name for https://dl-ssl.google.com/android/eclipse/ (with slash at the end)
Select the updates to install and then uncheck "Contact all update sites during install to find required software".


Friday, April 4, 2014

Interact with Azure Active Directory from Ruby on Rails


Ruby on Rails is a popular framework to build websites. You could follow the guidelines here to get started: http://guides.rubyonrails.org/. It gives templates to start a simple blog or a webapi, but it is somewhat forcing to Rail way. I mentioned all that as you may try it first time, you may not like the issues with dependencies. Here, i assume you know how to run simple website and update a controller. I will just give short example to use existing oauth library to access to Azure Active Directory. 

We will use Oauth2 library. Here is the github repo for that: https://github.com/intridea/oauth2
You should include require statement at the top of the controller. 

How does it work

WebApp needs to get the authorization code after the user enters the credential and page redirects with authorization code in query parameters. 

require 'oauth2'
class WelcomeController < ApplicationController # You need to configure a tenant at Azure Active Directory(AAD) to register web app and web service app # You will need two entries for these app at the AAD portal # You will put clientid and clientsecret for your web app here # ResourceId is the webservice that you registered # RedirectUri is registered for your web app CLIENT_ID = 'b6a42...' CLIENT_SECRET = 'TSbx..' AUTHORITY = 'https://login.windows.net/' AUTHORIZE_URL = "/yourtenant.onmicrosoft.com/oauth2/authorize" TOKEN_URL = "/yourtenant.onmicrosoft.com/oauth2/token" RESOURCE_ID = 'https://yourtenant.onmicrosoft.com/AllHandsTry' #ResourceId or ResourceURI that you registered at Azure Active Directory REDIRECT_URI = 'http://localhost:3000/welcome/callback' # landing page to redirect for authorization url, if token does not exist def index update_token if session['access_token'] # show main page and use token redirect_to welcome_use_token_path else # start authorization client = get_client a = client.auth_code.authorize_url(:client_id => CLIENT_ID, :resource => RESOURCE_ID, :redirect_uri => REDIRECT_URI) redirect_to(a) end end   # redirect will return to this page. You need to configure your redirectUri like: http://yoursite.com/callback def callback begin @code = params[:code] client = get_client # post token to mobile service api #token = client.auth_code.get_token(CGI.escape(@code), :redirect_uri => REDIRECT_URI) # id_token token.params["id_token"] #multi resource token token.params["resource"] token = client.auth_code.get_token(@code, :redirect_uri => REDIRECT_URI, ) session['access_token'] = token.token session['refresh_token'] = token.refresh_token session['expire_at'] = token.expire_at session['instance_url'] = token.params['instance_url'] redirect '/' rescue => exception output = '<html><body><p>' output += "Exception: #{exception.message}<br/>"+exception.backtrace.join('<br/>') output += '</p></body></html>' end end # if you want to update tokens def update_token puts "update token inside" token = session['access_token'] refresh_token = session['refresh_token'] expire_at = session['expire_at'] @access_token = OAuth2::AccessToken.from_hash(get_client, { :access_token => token, :refresh_token => refresh_token, :expire_at => expire_at, :header_format => 'Bearer %s' } ) if @access_token.expired? puts "refresh token" @access_token = @access_token.refresh!; session['access_token'] = @access_token.token session['refresh_token'] = @access_token.refresh_token session['expire_at'] = @access_token.expire_at session['instance_url'] = @access_token.params['instance_url'] end end # send request to a webservice to use a token def use_token # we got the token and now it will posted to the web service in the header # you can specify additional headers as well # token is included by default update_token conn = Faraday.new(:url => 'https://yoursite.azurewebsites.net/') do |faraday| faraday.request :url_encoded # form-encode POST params faraday.response :logger # log requests to STDOUT faraday.adapter Faraday.default_adapter # make requests with Net::HTTP end response = conn.get do |req| req.url '/api/WorkItem' req.headers['Content-Type'] = 'application/json' req.headers['Authorization'] = 'Bearer '+@access_token.token end @out = response.body end def get_client client = OAuth2::Client.new(CLIENT_ID, CLIENT_SECRET, :site => AUTHORITY, :authorize_url => AUTHORIZE_URL, :token_url => TOKEN_URL ) client end end

You could plug in your clientId, authority, resourceid after you configure your app at Azure Active Directory portal. I will try to extend this later. You can access the gist from here: https://gist.github.com/omercs/9918845

Azure Active Directory Library For Android



Azure Active Directory Library for Android

We have finally announced the Azure Active Directory(AAD) features at Build conference. It was exciting to hear about AAD at Keynotes.

This is not an official blog post, but I will show some details about the Android Library and app setup.  You can easily libraries access from https://github.com/MSOpenTech/azure-activedirectory-library-for-android and https://github.com/MSOpenTech/azure-activedirectory-library-for-ios

Prerequisites for Android development:



  • Install Git source control
  • Install Android SDK: https://developer.android.com/sdk/index.html?hl=sk
  • Make sure you can run some samples under the sdk/samples
  • Update SDKs and install SDK 15-19

  • It supports maven based installation, but you need to setup maven sdk deployer to actually do anything with latest Android SDKs since maven repos don't have the latest Android SDKs. You could skip Maven based installation and pull the dependent libraries directly. You could put them under the adal/libs folder.


    • Android-Support-v4: Fix project properties and it will be added
    • gson library: https://code.google.com/p/google-gson/downloads/list

    If you insist to setup maven environment, I will quickly walk through the details for your environment setup.

    Install Maven 3.1.1: http://maven.apache.org/download.cgi

    Maven helps to manage dependencies and build your project. Our sample app will be compiled with Eclipse ADT, so i am not forcing you to make maven based app.

    You need to put the latest android SDKs into local maven repo. You could use these commands to install SDK19 and support library:
    git clone https://github.com/mosabua/maven-android-sdk-deployer.git
    cd maven-android-sdk-deployer\platforms\android-19
    mvn clean install
    cd ..\..\extras\compatibility-v4
    mvn clean install
    You can clone and install from cmd line:
    git clone https://github.com/MSOpenTech/azure-activedirectory-library-for-android.git
    cd azure-activedirectory-library-for-android
    mvn clean install


    How to Add Android Library to your Project

    1. Add reference to your project as Android library. Please check here:http://developer.android.com/tools/projects/projects-eclipse.html
    2. Add project dependency for debugging in your project settings
    3. Update your project's AndroidManifest.xml file to include the authentication activity:
      <uses-permission android:name="android.permission.INTERNET" />
      <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
      <application
            android:allowBackup="true"
            android:debuggable="true"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
    
            <activity
                android:name="com.microsoft.adal.AuthenticationActivity"
                android:label="@string/title_login_hello_app" >
            </activity>
      ....
      <application/>

    Setup Native Client App at Azure Active Directory

    1.  Register your WEBAPI service app at Azure Active Directory(AAD),https://manage.windowsazure.com
      1. You need APP ID URI parameter to get token
    2. Register your client native app at AAD
      1. You need clientId and redirectUri parameters
      2. Select webapis in the list and give permission to previously registered(Step5) WebAPI

    Go to Azure portal:

    Create Directory entry if you don't have at Azure portal


     Click Active Directory to Create an App:
    Add an explication that you are developing
    Follow the wizard to setup the app.


    Define Native Client app to create Android app entry
    Redirect Uri needs to be unique. It is better to link to your domain. If you don't have, you can use your azure active directory address like "yourtenant.onmicrosoft.com".
    Define unique RedirecUri entry
    Configure the entry for permissions

    Update your app for App settings

    • Resource is required, Clientid is required. PromptBehavior helps to ask for credentials to skip cache and cookie. Callback ill be called after authorization code is exchanged for a token. It will have an object of AuthenticationResult, which has accesstoken, date expired, and idtoken info.
      1. You can always call acquireToken to handle caching, token refresh and credential prompt if required. Your callback implementation should handle the user cancellation for AuthenticationActivity. ADAL will return a cancellation error, if user cancels the credential entry.
    • Authority Url and ADFS

      ADFS is not recognized as production STS, so you need to turn of instance discovery and pass false for validation at AuthenticationContext constructor.
      Authority url needs to be in the form of STS instance and tenant name: https://login.windows.net/yourtenant.onmicrosoft.com

    Usage of AuthenticationContext

    1. Create an instance of AuthenticationContext at your main Activity. You can look at sample projects that is used for testing.
      mContext = new AuthenticationContext(MainActivity.this, authority, true); // This will use SharedPreferences as default cache
    
    mContext is a field in your activity. Copy this code block to handle the end of AuthenticationActivity after user enters credentials and receives authorization code:
     @Override
     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
         super.onActivityResult(requestCode, resultCode, data);
         if (mContext != null) {
             mContext.onActivityResult(requestCode, resultCode, data);
         }
     }
    To ask for a token, you need to define a callback:
    private AuthenticationCallback<AuthenticationResult> callback = new AuthenticationCallback<AuthenticationResult>() {
    
            @Override
            public void onError(Exception exc) {
                if (exc instanceof AuthenticationException) {
                    textViewStatus.setText("Cancelled");
                    Log.d(TAG, "Cancelled");
                } else {
                    textViewStatus.setText("Authentication error:" + exc.getMessage());
                    Log.d(TAG, "Authentication error:" + exc.getMessage());
                }
            }
    
            @Override
            public void onSuccess(AuthenticationResult result) {
                mResult = result;
    
                if (result == null || result.getAccessToken() == null
                        || result.getAccessToken().isEmpty()) {
                    textViewStatus.setText("Token is empty");
                    Log.d(TAG, "Token is empty");
                } else {
                    // request is successful
                    Log.d(TAG, "Status:" + result.getStatus() + " Expired:"
                            + result.getExpiresOn().toString());
                    textViewStatus.setText(PASSED);
                }
            }
        };
    Ask for a token:
     mContext.acquireToken(MainActivity.this, resource, clientId, redirect, userid, PromptBehavior.Auto, "",
                    callback);
    • Querying cache items

      ADAL provides Default cache in SharedPrefrecens with some simple cache query fucntions. You can get the current cache from AuthenticationContext with:
       ITokenCacheStore cache = mContext.getCache();
      
      You can also provide your cache implementation, if you want to customize it.
      mContext = new AuthenticationContext(MainActivity.this, authority, true, yourCache);
      

      Logger

      ADAL provides simple callback logger. You can set your callback for logging.
      Logger.getInstance().setExternalLogger(new ILogger() {
          @Override
          public void Log(String tag, String message, String additionalMessage, LogLevel level, ADALError errorCode) {
          ...
          }
      }
      // you can manage min log level as well
      Logger.getInstance().setLogLevel(Logger.LogLevel.Verbose);

    Multi Resource Refresh Token

    You may have several Web API services that you use in your app. When you get a token for resource1, you could use refresh token from resource1 to get access token for resource2. This will work if you use same authority, clientid and userid in the second call. Internal cache will help to reuse multi resource refresh tokens.
    mContext.acquireToken(MainActivity.this, resource1, clientId, redirect, userid, PromptBehavior.Auto, "",
                    callback);
    mContext.acquireToken(MainActivity.this, resource2, clientId, redirect, userid, PromptBehavior.Auto, "",
                    callback);
    Second call here will not display prompt screen. It will only send refresh token web request.

    Happy coding!
    ------------------------The END------------------------