Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Integrate ADFS / Azure AD with Rails

Integrate ADFS / Azure AD with Rails

Luka Huang

August 12, 2018
Tweet

More Decks by Luka Huang

Other Decks in Programming

Transcript

  1. Hi, I am Luka Huang ( Hi, I am Luka

    Huang ( ). ). A backend engineer work for A backend engineer work for .. @codingluka @codingluka Splashtop Splashtop
  2. How to integrate ADFS or Azure How to integrate ADFS

    or Azure AD with Rails AD with Rails
  3. Three Questions: Three Questions: What is AD? What is AD?

    What is SAML? What is SAML? Why we integrate AD with Rails? Why we integrate AD with Rails?
  4. SAML - Security Assertion Markup Language SAML - Security Assertion

    Markup Language Security 安全 Security 安全 Assestion 斷⾔ Assestion 斷⾔ Markup Language 標記式語⾔ Markup Language 標記式語⾔
  5. 名詞解釋: 名詞解釋: IdP – Identity Provider IdP – Identity Provider

    SP – Service Provider SP – Service Provider SSO – Single Sign-on SSO – Single Sign-on
  6. Topics Topics Introduce SAML in details Introduce SAML in details

    Introduce SSO and SLO Introduce SSO and SLO Introduce ADFS? Introduce ADFS? Introduce Azure AD? Introduce Azure AD? How to integrate ADFS/Azure AD with Rails How to integrate ADFS/Azure AD with Rails
  7. Step 2 - Service Provider ⽤ Form 的型式發出 Step 2

    - Service Provider ⽤ Form 的型式發出 Request 通知 Browser Request 通知 Browser < <form form method method= ="post" "post" action action= ="https://idp.example.org/SAML2/SSO "https://idp.example.org/SAML2/SSO < <input input type type= ="hidden" "hidden" name name= ="SAMLRequest" "SAMLRequest" value value= ="<samlp:Aut "<samlp:Aut ... other input parameter.... ... other input parameter.... < <input input type type= ="submit" "submit" value value= ="Submit" "Submit" /> /> </ </form form> > < <javascript javascript> > document.form[0].submit(); document.form[0].submit(); </ </javascript javascript> >
  8. Step 3 - POST SAML infos to identity provider Step

    3 - POST SAML infos to identity provider < <samlp:AuthnRequest samlp:AuthnRequest xmlns:samlp xmlns:samlp= ="urn:oasis:names:tc:SAML:2.0:protocol" "urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml xmlns:saml= ="urn:oasis:names:tc:SAML:2.0:assertion" "urn:oasis:names:tc:SAML:2.0:assertion" ID ID= ="aaf23196-1773-2113-474a-fe114412ab72" "aaf23196-1773-2113-474a-fe114412ab72" Version Version= ="2.0" "2.0" IssueInstant IssueInstant= ="2004-12-05T09:21:59" "2004-12-05T09:21:59" AssertionConsumerServiceIndex AssertionConsumerServiceIndex= ="0" "0" AttributeConsumingServiceIndex AttributeConsumingServiceIndex= ="0" "0"> > < <saml:Issuer saml:Issuer> >https://identity-provider.example.com/SAML2 https://identity-provider.example.com/SAML2< < < <samlp:NameIDPolicy samlp:NameIDPolicy AllowCreate AllowCreate= ="true" "true" Format Format= ="urn:oasis:names:tc:SAML:2.0:nameid-format:trans "urn:oasis:names:tc:SAML:2.0:nameid-format:trans </ </samlp:AuthnRequest samlp:AuthnRequest> >
  9. Step 6 傳送的資料 Step 6 傳送的資料 < <form form method

    method= ="post" "post" action action= ="https://service-provider-example "https://service-provider-example < <input input type type= ="hidden" "hidden" name name= ="SAMLResponse" "SAMLResponse" value value= ="<samlp:Re "<samlp:Re < <input input type type= ="hidden" "hidden" name name= ="RelayState" "RelayState" value value= ="''token''" "''token''" ... ... < <input input type type= ="submit" "submit" value value= ="Submit" "Submit" /> /> </ </form form> > < <javascript javascript> > document.form[0].submit(); document.form[0].submit(); </ </javascript javascript> >
  10. Step 7 - 最重要的⼀步 Step 7 - 最重要的⼀步 Browser 從

    Identity Provider 拿到 Assertion 後, Browser 從 Identity Provider 拿到 Assertion 後, 由 Service Provider 的 Assertion Consumer 由 Service Provider 的 Assertion Consumer Service 做驗證 Service 做驗證 驗證成功即可確定 Browser 為合法使⽤者。 驗證成功即可確定 Browser 為合法使⽤者。
  11. 資料範例,注意到裡⾯有⼀個 資料範例,注意到裡⾯有⼀個 <saml:Assertion <saml:Assertion ... ... ,即是認證的關鍵 ,即是認證的關鍵 < <samlp:Response

    samlp:Response xmlns:samlp xmlns:samlp= ="urn:oasis:names:tc:SAML:2.0:protocol" "urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml xmlns:saml= ="urn:oasis:names:tc:SAML:2.0:assertion" "urn:oasis:names:tc:SAML:2.0:assertion" ID ID= ="identifier_2" "identifier_2" InResponseTo InResponseTo= ="identifier_1" "identifier_1" Version Version= ="2.0" "2.0" IssueInstant IssueInstant= ="2004-12-05T09:22:05" "2004-12-05T09:22:05" Destination Destination= ="https://sp.example.com/SAML2/SSO/POST" "https://sp.example.com/SAML2/SSO/POST"> > < <saml:Issuer saml:Issuer> >https://idp.example.org/SAML2 https://idp.example.org/SAML2</ </saml:Issuer saml:Issuer> > < <samlp:Status samlp:Status> > < <samlp:StatusCode samlp:StatusCode Value Value= ="urn:oasis:names:tc:SAML:2.0:status:Success" "urn:oasis:names:tc:SAML:2.0:status:Success"> ></ </ </ </samlp:Status samlp:Status> > < <saml:Assertion saml:Assertion xmlns:saml xmlns:saml= ="urn:oasis:names:tc:SAML:2 0:assertion" "urn:oasis:names:tc:SAML:2.0:assertion"
  12. Assertion - 斷⾔使⽤者是否合法 Assertion - 斷⾔使⽤者是否合法 < <saml:Assertion saml:Assertion xmlns:saml

    xmlns:saml= ="urn:oasis:names:tc:SAML:2.0:assertion" "urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs xmlns:xs= ="http://www.w3.org/2001/XMLSchema" "http://www.w3.org/2001/XMLSchema" xmlns:xsi xmlns:xsi= ="http://www.w3.org/2001/XMLSchema-instance" "http://www.w3.org/2001/XMLSchema-instance" ID ID= ="b07b804c-7c29-ea16-7300-4f3d6f7928ac" "b07b804c-7c29-ea16-7300-4f3d6f7928ac" Version Version= ="2.0" "2.0" IssueInstant IssueInstant= ="2004-12-05T09:22:05" "2004-12-05T09:22:05"> > < <saml:Issuer saml:Issuer> >https://idp.example.org/SAML2 https://idp.example.org/SAML2</ </saml:Issuer saml:Issuer> > < <ds:Signature ds:Signature xmlns:ds xmlns:ds= ="http://www.w3.org/2000/09/xmldsig#" "http://www.w3.org/2000/09/xmldsig#"> >... ...</ </ds:Si ds:Si < <saml:Subject saml:Subject> > .......... .......... </ </saml:Subject saml:Subject> > < <saml:Conditions saml:Conditions .........
  13. SAML Single Logout - What You Need to Know |

    SAML Single Logout - What You Need to Know |
  14. How to integrate Azure AD / How to integrate Azure

    AD / ADFS with Rails? ADFS with Rails?
  15. metadata metadata class class SamlController SamlController < ApplicationController < ApplicationController

    . . . . . . def def metadata metadata settings = Account.get_saml_settings(get_url_base) settings = Account.get_saml_settings(get_url_base) meta = OneLogin::RubySaml::Metadata.new meta = OneLogin::RubySaml::Metadata.new render render :xml :xml => meta.generate(settings, => meta.generate(settings, true true) ) end end . . . . .
  16. SAML settings SAML settings class class Account Account < ActiveRecord::Base

    < ActiveRecord::Base def def self self. .get_saml_settings get_saml_settings(url_base) (url_base) # this is just for testing purposes. # this is just for testing purposes. # should retrieve SAML-settings based on subdomain, IP-ad # should retrieve SAML-settings based on subdomain, IP-ad settings = OneLogin::RubySaml::Settings.new settings = OneLogin::RubySaml::Settings.new url_base url_base || ||= = "http://localhost:3000" "http://localhost:3000" # Example settings data, replace this values! # Example settings data, replace this values! # When disabled, saml validation errors will raise an exc # When disabled, saml validation errors will raise an exc settings.soft = settings.soft = true true #SP section #SP section settings issuer = url base + settings.issuer = url base + "/sa "/sa
  17. SSO SSO class class SamlController SamlController < ApplicationController < ApplicationController

    . . . . . . def def sso sso settings = Account.get_saml_settings(get_url_base) settings = Account.get_saml_settings(get_url_base) if if settings. settings.nil nil? ? render render :action :action => => :no_settings :no_settings return return end end request = OneLogin::RubySaml::Authrequest.new request = OneLogin::RubySaml::Authrequest.new redirect to(request create(settings)) redirect to(request.create(settings))
  18. ACS - Assertion Consumer Service ACS - Assertion Consumer Service

    class class SamlController SamlController < ApplicationController < ApplicationController . . . . . . def def acs acs settings = Account.get_saml_settings(get_url_base) settings = Account.get_saml_settings(get_url_base) response = OneLogin::RubySaml::Response.new(params[ response = OneLogin::RubySaml::Response.new(params[:SAMLR :SAMLR if if response.is_valid? response.is_valid? session[ session[:nameid :nameid] = response.nameid ] = response.nameid session[ session[:attributes :attributes] = response.attributes ] = response.attributes @attrs = session[ @attrs = session[:attributes :attributes] ] logger info logger.info "Sucessfully logged" "Sucessfully logged"
  19. Part 2 - ADFS Part 2 - ADFS 我準備了⼀個教學,說明如何設定 ADFS

    跟 Rails 串 我準備了⼀個教學,說明如何設定 ADFS 跟 Rails 串 接。 接。 StevenTTuD/how-to-set-up-adfs-with-saml StevenTTuD/how-to-set-up-adfs-with-saml