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

2 comments:

  1. This is from 2014. Is there a more current version or any updates? I have not been able to get all this to work :-(

    ReplyDelete

Hey!
Let me know what you think?