maestrano 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
 - data/.gitignore +34 -0
 - data/Gemfile +2 -0
 - data/Gemfile.lock +43 -0
 - data/LICENSE +21 -0
 - data/README.md +4 -0
 - data/Rakefile +32 -0
 - data/bin/maestrano-console +9 -0
 - data/lib/maestrano.rb +114 -0
 - data/lib/maestrano/account/bill.rb +14 -0
 - data/lib/maestrano/api/error/authentication_error.rb +8 -0
 - data/lib/maestrano/api/error/base_error.rb +24 -0
 - data/lib/maestrano/api/error/connection_error.rb +8 -0
 - data/lib/maestrano/api/error/invalid_request_error.rb +14 -0
 - data/lib/maestrano/api/list_object.rb +37 -0
 - data/lib/maestrano/api/object.rb +187 -0
 - data/lib/maestrano/api/operation/base.rb +216 -0
 - data/lib/maestrano/api/operation/create.rb +18 -0
 - data/lib/maestrano/api/operation/delete.rb +13 -0
 - data/lib/maestrano/api/operation/list.rb +18 -0
 - data/lib/maestrano/api/operation/update.rb +59 -0
 - data/lib/maestrano/api/resource.rb +39 -0
 - data/lib/maestrano/api/util.rb +121 -0
 - data/lib/maestrano/saml/attribute_value.rb +15 -0
 - data/lib/maestrano/saml/metadata.rb +64 -0
 - data/lib/maestrano/saml/request.rb +93 -0
 - data/lib/maestrano/saml/response.rb +201 -0
 - data/lib/maestrano/saml/schemas/saml20assertion_schema.xsd +283 -0
 - data/lib/maestrano/saml/schemas/saml20protocol_schema.xsd +302 -0
 - data/lib/maestrano/saml/schemas/xenc_schema.xsd +146 -0
 - data/lib/maestrano/saml/schemas/xmldsig_schema.xsd +318 -0
 - data/lib/maestrano/saml/settings.rb +37 -0
 - data/lib/maestrano/saml/validation_error.rb +7 -0
 - data/lib/maestrano/sso.rb +81 -0
 - data/lib/maestrano/sso/base_group.rb +31 -0
 - data/lib/maestrano/sso/base_user.rb +75 -0
 - data/lib/maestrano/sso/group.rb +24 -0
 - data/lib/maestrano/sso/session.rb +63 -0
 - data/lib/maestrano/sso/user.rb +34 -0
 - data/lib/maestrano/version.rb +3 -0
 - data/lib/maestrano/xml_security/signed_document.rb +170 -0
 - data/maestrano.gemspec +32 -0
 - data/test/helpers/api_helpers.rb +82 -0
 - data/test/helpers/saml_helpers.rb +62 -0
 - data/test/maestrano/account/bill_test.rb +48 -0
 - data/test/maestrano/api/list_object_test.rb +20 -0
 - data/test/maestrano/api/object_test.rb +28 -0
 - data/test/maestrano/api/resource_test.rb +343 -0
 - data/test/maestrano/api/util_test.rb +31 -0
 - data/test/maestrano/maestrano_test.rb +49 -0
 - data/test/maestrano/saml/request_test.rb +168 -0
 - data/test/maestrano/saml/response_test.rb +290 -0
 - data/test/maestrano/saml/settings_test.rb +51 -0
 - data/test/maestrano/sso/base_group_test.rb +54 -0
 - data/test/maestrano/sso/base_user_test.rb +114 -0
 - data/test/maestrano/sso/group_test.rb +47 -0
 - data/test/maestrano/sso/session_test.rb +108 -0
 - data/test/maestrano/sso/user_test.rb +65 -0
 - data/test/maestrano/sso_test.rb +81 -0
 - data/test/maestrano/xml_security/signed_document.rb +163 -0
 - data/test/support/saml/certificates/certificate1 +12 -0
 - data/test/support/saml/certificates/r1_certificate2_base64 +1 -0
 - data/test/support/saml/responses/adfs_response_sha1.xml +46 -0
 - data/test/support/saml/responses/adfs_response_sha256.xml +46 -0
 - data/test/support/saml/responses/adfs_response_sha384.xml +46 -0
 - data/test/support/saml/responses/adfs_response_sha512.xml +46 -0
 - data/test/support/saml/responses/no_signature_ns.xml +48 -0
 - data/test/support/saml/responses/open_saml_response.xml +56 -0
 - data/test/support/saml/responses/r1_response6.xml.base64 +1 -0
 - data/test/support/saml/responses/response1.xml.base64 +1 -0
 - data/test/support/saml/responses/response2.xml.base64 +79 -0
 - data/test/support/saml/responses/response3.xml.base64 +66 -0
 - data/test/support/saml/responses/response4.xml.base64 +93 -0
 - data/test/support/saml/responses/response5.xml.base64 +102 -0
 - data/test/support/saml/responses/response_with_ampersands.xml +139 -0
 - data/test/support/saml/responses/response_with_ampersands.xml.base64 +93 -0
 - data/test/support/saml/responses/response_with_multiple_attribute_values.xml +57 -0
 - data/test/support/saml/responses/simple_saml_php.xml +71 -0
 - data/test/support/saml/responses/starfield_response.xml.base64 +1 -0
 - data/test/support/saml/responses/wrapped_response_2.xml.base64 +150 -0
 - data/test/test_helper.rb +46 -0
 - metadata +305 -0
 
| 
         @@ -0,0 +1,37 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Maestrano
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Saml
         
     | 
| 
      
 3 
     | 
    
         
            +
                class Settings
         
     | 
| 
      
 4 
     | 
    
         
            +
                  NAMEID_EMAIL_ADDRESS                 = 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress'
         
     | 
| 
      
 5 
     | 
    
         
            +
                  NAMEID_X509_SUBJECT_NAME             = 'urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName'
         
     | 
| 
      
 6 
     | 
    
         
            +
                  NAMEID_WINDOWS_DOMAIN_QUALIFIED_NAME = 'urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName'
         
     | 
| 
      
 7 
     | 
    
         
            +
                  NAMEID_KERBEROS   = 'urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos'
         
     | 
| 
      
 8 
     | 
    
         
            +
                  NAMEID_ENTITY     = 'urn:oasis:names:tc:SAML:2.0:nameid-format:entity'
         
     | 
| 
      
 9 
     | 
    
         
            +
                  NAMEID_TRANSIENT  = 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'
         
     | 
| 
      
 10 
     | 
    
         
            +
                  NAMEID_PERSISTENT = 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
         
     | 
| 
      
 11 
     | 
    
         
            +
                  PROTOCOL_BINDING_POST = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'
         
     | 
| 
      
 12 
     | 
    
         
            +
                  
         
     | 
| 
      
 13 
     | 
    
         
            +
                  def initialize(overrides = {})
         
     | 
| 
      
 14 
     | 
    
         
            +
                    config = DEFAULTS.merge(overrides)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    config.each do |k,v|
         
     | 
| 
      
 16 
     | 
    
         
            +
                      acc = "#{k.to_s}=".to_sym
         
     | 
| 
      
 17 
     | 
    
         
            +
                      self.send(acc, v) if self.respond_to? acc
         
     | 
| 
      
 18 
     | 
    
         
            +
                    end
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
                  attr_accessor :assertion_consumer_service_url, :issuer, :sp_name_qualifier
         
     | 
| 
      
 21 
     | 
    
         
            +
                  attr_accessor :idp_sso_target_url, :idp_cert_fingerprint, :idp_cert, :name_identifier_format
         
     | 
| 
      
 22 
     | 
    
         
            +
                  attr_accessor :authn_context
         
     | 
| 
      
 23 
     | 
    
         
            +
                  attr_accessor :idp_slo_target_url
         
     | 
| 
      
 24 
     | 
    
         
            +
                  attr_accessor :name_identifier_value
         
     | 
| 
      
 25 
     | 
    
         
            +
                  attr_accessor :sessionindex
         
     | 
| 
      
 26 
     | 
    
         
            +
                  attr_accessor :assertion_consumer_logout_service_url
         
     | 
| 
      
 27 
     | 
    
         
            +
                  attr_accessor :compress_request
         
     | 
| 
      
 28 
     | 
    
         
            +
                  attr_accessor :double_quote_xml_attribute_values
         
     | 
| 
      
 29 
     | 
    
         
            +
                  attr_accessor :passive
         
     | 
| 
      
 30 
     | 
    
         
            +
                  attr_accessor :protocol_binding
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  private
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  DEFAULTS = {:compress_request => true, :double_quote_xml_attribute_values => false}
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,81 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Maestrano
         
     | 
| 
      
 2 
     | 
    
         
            +
              module SSO
         
     | 
| 
      
 3 
     | 
    
         
            +
                # Return the saml_settings based on
         
     | 
| 
      
 4 
     | 
    
         
            +
                # Maestrano configuration
         
     | 
| 
      
 5 
     | 
    
         
            +
                def self.saml_settings
         
     | 
| 
      
 6 
     | 
    
         
            +
                  settings = Maestrano::Saml::Settings.new
         
     | 
| 
      
 7 
     | 
    
         
            +
                  settings.assertion_consumer_service_url = self.consume_url
         
     | 
| 
      
 8 
     | 
    
         
            +
                  settings.issuer                         = Maestrano.param('app_host')
         
     | 
| 
      
 9 
     | 
    
         
            +
                  settings.idp_sso_target_url             = self.idp_url
         
     | 
| 
      
 10 
     | 
    
         
            +
                  settings.idp_cert_fingerprint           = Maestrano.param('sso_x509_fingerprint')
         
     | 
| 
      
 11 
     | 
    
         
            +
                  settings.name_identifier_format         = Maestrano.param('sso_name_id_format')
         
     | 
| 
      
 12 
     | 
    
         
            +
                  settings
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
                
         
     | 
| 
      
 15 
     | 
    
         
            +
                # Build a new SAML Request
         
     | 
| 
      
 16 
     | 
    
         
            +
                def self.build_request(get_params = {})
         
     | 
| 
      
 17 
     | 
    
         
            +
                  Maestrano::Saml::Request.new(get_params)
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
                
         
     | 
| 
      
 20 
     | 
    
         
            +
                # Build a new SAML response
         
     | 
| 
      
 21 
     | 
    
         
            +
                def self.build_response(saml_post_param)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  Maestrano::Saml::Response.new(saml_post_param)
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
                
         
     | 
| 
      
 25 
     | 
    
         
            +
                def self.enabled?
         
     | 
| 
      
 26 
     | 
    
         
            +
                  !!Maestrano.param('sso_enabled')
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
                
         
     | 
| 
      
 29 
     | 
    
         
            +
                def self.init_url
         
     | 
| 
      
 30 
     | 
    
         
            +
                  host = Maestrano.param('app_host')
         
     | 
| 
      
 31 
     | 
    
         
            +
                  path = Maestrano.param('sso_app_init_path')
         
     | 
| 
      
 32 
     | 
    
         
            +
                  return "#{host}#{path}"
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
                
         
     | 
| 
      
 35 
     | 
    
         
            +
                def self.consume_url
         
     | 
| 
      
 36 
     | 
    
         
            +
                  host = Maestrano.param('app_host')
         
     | 
| 
      
 37 
     | 
    
         
            +
                  path = Maestrano.param('sso_app_consume_path')
         
     | 
| 
      
 38 
     | 
    
         
            +
                  return "#{host}#{path}"
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
                
         
     | 
| 
      
 41 
     | 
    
         
            +
                def self.logout_url
         
     | 
| 
      
 42 
     | 
    
         
            +
                  host = Maestrano.param('api_host')
         
     | 
| 
      
 43 
     | 
    
         
            +
                  path = '/app_logout'
         
     | 
| 
      
 44 
     | 
    
         
            +
                  return "#{host}#{path}"
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
                
         
     | 
| 
      
 47 
     | 
    
         
            +
                def self.unauthorized_url
         
     | 
| 
      
 48 
     | 
    
         
            +
                  host = Maestrano.param('api_host')
         
     | 
| 
      
 49 
     | 
    
         
            +
                  path = '/app_access_unauthorized'
         
     | 
| 
      
 50 
     | 
    
         
            +
                  return "#{host}#{path}";
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
                
         
     | 
| 
      
 53 
     | 
    
         
            +
                def self.idp_url
         
     | 
| 
      
 54 
     | 
    
         
            +
                  host = Maestrano.param('api_host')
         
     | 
| 
      
 55 
     | 
    
         
            +
                  api_base = Maestrano.param('api_base')
         
     | 
| 
      
 56 
     | 
    
         
            +
                  endpoint = 'auth/saml'
         
     | 
| 
      
 57 
     | 
    
         
            +
                  return "#{host}#{api_base}#{endpoint}"
         
     | 
| 
      
 58 
     | 
    
         
            +
                end
         
     | 
| 
      
 59 
     | 
    
         
            +
                
         
     | 
| 
      
 60 
     | 
    
         
            +
                def self.session_check_url(user_uid,sso_session) 
         
     | 
| 
      
 61 
     | 
    
         
            +
                  host = Maestrano.param('api_host')
         
     | 
| 
      
 62 
     | 
    
         
            +
                  api_base = Maestrano.param('api_base')
         
     | 
| 
      
 63 
     | 
    
         
            +
                  endpoint = 'auth/saml'
         
     | 
| 
      
 64 
     | 
    
         
            +
                  return URI.escape("#{host}#{api_base}#{endpoint}/#{user_uid}?session=#{sso_session}")
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
                
         
     | 
| 
      
 67 
     | 
    
         
            +
                # Set maestrano attributes in session
         
     | 
| 
      
 68 
     | 
    
         
            +
                # Takes the BaseUser hash representation and current session
         
     | 
| 
      
 69 
     | 
    
         
            +
                # in arguments
         
     | 
| 
      
 70 
     | 
    
         
            +
                def self.set_session(session, auth)
         
     | 
| 
      
 71 
     | 
    
         
            +
                  if auth && (extra = (auth[:extra] || auth['extra'])) && (sso_session = (extra[:session] || extra['session']))
         
     | 
| 
      
 72 
     | 
    
         
            +
                    session[:mno_uid] = (sso_session[:uid] || sso_session['uid'])
         
     | 
| 
      
 73 
     | 
    
         
            +
                    session[:mno_session] = (sso_session[:token] || sso_session['token'])
         
     | 
| 
      
 74 
     | 
    
         
            +
                    if recheck = (sso_session[:recheck] || sso_session['recheck'])
         
     | 
| 
      
 75 
     | 
    
         
            +
                      session[:mno_session_recheck] = recheck.utc.iso8601
         
     | 
| 
      
 76 
     | 
    
         
            +
                    end
         
     | 
| 
      
 77 
     | 
    
         
            +
                    session[:mno_group_uid] = (sso_session[:group_uid] || sso_session['group_uid'])
         
     | 
| 
      
 78 
     | 
    
         
            +
                  end
         
     | 
| 
      
 79 
     | 
    
         
            +
                end
         
     | 
| 
      
 80 
     | 
    
         
            +
              end
         
     | 
| 
      
 81 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,31 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Maestrano
         
     | 
| 
      
 2 
     | 
    
         
            +
              module SSO
         
     | 
| 
      
 3 
     | 
    
         
            +
                class BaseGroup
         
     | 
| 
      
 4 
     | 
    
         
            +
                  attr_accessor :local_id
         
     | 
| 
      
 5 
     | 
    
         
            +
                  attr_reader :uid,:country, :company_name, :free_trial_end_at
         
     | 
| 
      
 6 
     | 
    
         
            +
                  
         
     | 
| 
      
 7 
     | 
    
         
            +
                  # Initializer
         
     | 
| 
      
 8 
     | 
    
         
            +
                  # @param Maestrano::SAML::Response
         
     | 
| 
      
 9 
     | 
    
         
            +
                  def initialize(saml_response)
         
     | 
| 
      
 10 
     | 
    
         
            +
                    att = saml_response.attributes
         
     | 
| 
      
 11 
     | 
    
         
            +
                    @uid = att['group_uid']
         
     | 
| 
      
 12 
     | 
    
         
            +
                    @country = att['country']
         
     | 
| 
      
 13 
     | 
    
         
            +
                    @free_trial_end_at = Time.iso8601(att['group_end_free_trial'])
         
     | 
| 
      
 14 
     | 
    
         
            +
                    @company_name = att['company_name']
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
                  
         
     | 
| 
      
 17 
     | 
    
         
            +
                  def to_hash
         
     | 
| 
      
 18 
     | 
    
         
            +
                    {
         
     | 
| 
      
 19 
     | 
    
         
            +
                      provider: 'maestrano',
         
     | 
| 
      
 20 
     | 
    
         
            +
                      uid: self.uid,
         
     | 
| 
      
 21 
     | 
    
         
            +
                      info: {
         
     | 
| 
      
 22 
     | 
    
         
            +
                        free_trial_end_at: self.free_trial_end_at,
         
     | 
| 
      
 23 
     | 
    
         
            +
                        company_name: self.company_name,
         
     | 
| 
      
 24 
     | 
    
         
            +
                        country: self.country,
         
     | 
| 
      
 25 
     | 
    
         
            +
                      },
         
     | 
| 
      
 26 
     | 
    
         
            +
                      extra: {}
         
     | 
| 
      
 27 
     | 
    
         
            +
                    }
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,75 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Maestrano
         
     | 
| 
      
 2 
     | 
    
         
            +
              module SSO
         
     | 
| 
      
 3 
     | 
    
         
            +
                class BaseUser
         
     | 
| 
      
 4 
     | 
    
         
            +
                  attr_accessor :local_id
         
     | 
| 
      
 5 
     | 
    
         
            +
                  attr_reader :sso_session,:sso_session_recheck,
         
     | 
| 
      
 6 
     | 
    
         
            +
                    :group_uid,:group_role,:uid,:virtual_uid,:email,
         
     | 
| 
      
 7 
     | 
    
         
            +
                    :virtual_email,:first_name, :last_name,:country, :company_name
         
     | 
| 
      
 8 
     | 
    
         
            +
                  
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # Initializer
         
     | 
| 
      
 10 
     | 
    
         
            +
                  # @param Maestrano::SAML::Response
         
     | 
| 
      
 11 
     | 
    
         
            +
                  def initialize(saml_response)
         
     | 
| 
      
 12 
     | 
    
         
            +
                    att = saml_response.attributes
         
     | 
| 
      
 13 
     | 
    
         
            +
                    @sso_session = att['mno_session']
         
     | 
| 
      
 14 
     | 
    
         
            +
                    @sso_session_recheck = Time.iso8601(att['mno_session_recheck'])
         
     | 
| 
      
 15 
     | 
    
         
            +
                    @group_uid = att['group_uid']
         
     | 
| 
      
 16 
     | 
    
         
            +
                    @group_role = att['group_role']
         
     | 
| 
      
 17 
     | 
    
         
            +
                    @uid = att['uid']
         
     | 
| 
      
 18 
     | 
    
         
            +
                    @virtual_uid = att['virtual_uid']
         
     | 
| 
      
 19 
     | 
    
         
            +
                    @email = att['email']
         
     | 
| 
      
 20 
     | 
    
         
            +
                    @virtual_email = att['virtual_email']
         
     | 
| 
      
 21 
     | 
    
         
            +
                    @first_name = att['name']
         
     | 
| 
      
 22 
     | 
    
         
            +
                    @last_name = att['surname']
         
     | 
| 
      
 23 
     | 
    
         
            +
                    @country = att['country']
         
     | 
| 
      
 24 
     | 
    
         
            +
                    @company_name = att['company_name']
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
                  
         
     | 
| 
      
 27 
     | 
    
         
            +
                  def to_uid
         
     | 
| 
      
 28 
     | 
    
         
            +
                    if Maestrano.param('user_creation_mode') == 'real'
         
     | 
| 
      
 29 
     | 
    
         
            +
                      return self.uid
         
     | 
| 
      
 30 
     | 
    
         
            +
                    else
         
     | 
| 
      
 31 
     | 
    
         
            +
                      return self.virtual_uid
         
     | 
| 
      
 32 
     | 
    
         
            +
                    end
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
                  
         
     | 
| 
      
 35 
     | 
    
         
            +
                  def to_email
         
     | 
| 
      
 36 
     | 
    
         
            +
                    if Maestrano.param('user_creation_mode') == 'real'
         
     | 
| 
      
 37 
     | 
    
         
            +
                      return self.email
         
     | 
| 
      
 38 
     | 
    
         
            +
                    else
         
     | 
| 
      
 39 
     | 
    
         
            +
                      return self.virtual_email
         
     | 
| 
      
 40 
     | 
    
         
            +
                    end
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
                  
         
     | 
| 
      
 43 
     | 
    
         
            +
                  # Hash representation of the resource
         
     | 
| 
      
 44 
     | 
    
         
            +
                  def to_hash
         
     | 
| 
      
 45 
     | 
    
         
            +
                    {
         
     | 
| 
      
 46 
     | 
    
         
            +
                      provider: 'maestrano',
         
     | 
| 
      
 47 
     | 
    
         
            +
                      uid: self.to_uid,
         
     | 
| 
      
 48 
     | 
    
         
            +
                      info: {
         
     | 
| 
      
 49 
     | 
    
         
            +
                        email: self.to_email,
         
     | 
| 
      
 50 
     | 
    
         
            +
                        first_name: self.first_name,
         
     | 
| 
      
 51 
     | 
    
         
            +
                        last_name: self.last_name,
         
     | 
| 
      
 52 
     | 
    
         
            +
                        country: self.country,
         
     | 
| 
      
 53 
     | 
    
         
            +
                        company_name: self.company_name,
         
     | 
| 
      
 54 
     | 
    
         
            +
                      },
         
     | 
| 
      
 55 
     | 
    
         
            +
                      extra: {
         
     | 
| 
      
 56 
     | 
    
         
            +
                        uid: self.uid,
         
     | 
| 
      
 57 
     | 
    
         
            +
                        virtual_uid: self.virtual_uid,
         
     | 
| 
      
 58 
     | 
    
         
            +
                        real_email: self.email,
         
     | 
| 
      
 59 
     | 
    
         
            +
                        virtual_email: self.virtual_email,
         
     | 
| 
      
 60 
     | 
    
         
            +
                        group: {
         
     | 
| 
      
 61 
     | 
    
         
            +
                          uid: self.group_uid,
         
     | 
| 
      
 62 
     | 
    
         
            +
                          role: self.group_role,
         
     | 
| 
      
 63 
     | 
    
         
            +
                        },
         
     | 
| 
      
 64 
     | 
    
         
            +
                        session: {
         
     | 
| 
      
 65 
     | 
    
         
            +
                          uid: self.uid,
         
     | 
| 
      
 66 
     | 
    
         
            +
                          token: self.sso_session,
         
     | 
| 
      
 67 
     | 
    
         
            +
                          recheck: self.sso_session_recheck,
         
     | 
| 
      
 68 
     | 
    
         
            +
                          group_uid: self.group_uid
         
     | 
| 
      
 69 
     | 
    
         
            +
                        },
         
     | 
| 
      
 70 
     | 
    
         
            +
                      }
         
     | 
| 
      
 71 
     | 
    
         
            +
                    }
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
                end
         
     | 
| 
      
 74 
     | 
    
         
            +
              end
         
     | 
| 
      
 75 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,24 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Maestrano
         
     | 
| 
      
 2 
     | 
    
         
            +
              module SSO
         
     | 
| 
      
 3 
     | 
    
         
            +
                module Group
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def find_for_maestrano_auth(auth)
         
     | 
| 
      
 5 
     | 
    
         
            +
                    # E.g with Rails
         
     | 
| 
      
 6 
     | 
    
         
            +
                    # where(auth.slice(:provider, :uid)).first_or_create do |group|
         
     | 
| 
      
 7 
     | 
    
         
            +
                    #   group.provider = auth[:provider]
         
     | 
| 
      
 8 
     | 
    
         
            +
                    #   group.uid = auth[:uid]
         
     | 
| 
      
 9 
     | 
    
         
            +
                    #   group.name = (auth[:info][:company_name] || 'Your Group')
         
     | 
| 
      
 10 
     | 
    
         
            +
                    #   group.country = auth[:info][:country]
         
     | 
| 
      
 11 
     | 
    
         
            +
                    # end
         
     | 
| 
      
 12 
     | 
    
         
            +
                    raise NoMethodError, "You need to override find_for_maestrano_auth in your #{self.class.name} model"
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
                  
         
     | 
| 
      
 15 
     | 
    
         
            +
                  def maestrano?
         
     | 
| 
      
 16 
     | 
    
         
            +
                    if self.respond_to?(:provider)
         
     | 
| 
      
 17 
     | 
    
         
            +
                      return self.provider.to_s == 'maestrano'
         
     | 
| 
      
 18 
     | 
    
         
            +
                    else
         
     | 
| 
      
 19 
     | 
    
         
            +
                      raise NoMethodError, "You need to override maestrano? in your #{self.class.name} model"
         
     | 
| 
      
 20 
     | 
    
         
            +
                    end
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,63 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Maestrano
         
     | 
| 
      
 2 
     | 
    
         
            +
              module SSO
         
     | 
| 
      
 3 
     | 
    
         
            +
                class Session
         
     | 
| 
      
 4 
     | 
    
         
            +
                  attr_accessor :session, :uid, :session_token, :recheck
         
     | 
| 
      
 5 
     | 
    
         
            +
                  
         
     | 
| 
      
 6 
     | 
    
         
            +
                  def initialize(session)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    self.session = session
         
     | 
| 
      
 8 
     | 
    
         
            +
                    self.uid = (self.session['mno_uid'] || self.session[:mno_uid])
         
     | 
| 
      
 9 
     | 
    
         
            +
                    self.session_token = (self.session['mno_session'] || self.session[:mno_session])
         
     | 
| 
      
 10 
     | 
    
         
            +
                    if recheck = (self.session['mno_session_recheck'] || self.session[:mno_session_recheck])
         
     | 
| 
      
 11 
     | 
    
         
            +
                      self.recheck = Time.iso8601(recheck)
         
     | 
| 
      
 12 
     | 
    
         
            +
                    end
         
     | 
| 
      
 13 
     | 
    
         
            +
                    
         
     | 
| 
      
 14 
     | 
    
         
            +
                    if self.uid.nil? || self.session_token.nil? || self.recheck.nil?
         
     | 
| 
      
 15 
     | 
    
         
            +
                      $stderr.puts "WARNING: Maestrano session information missing. User will have to relogin"
         
     | 
| 
      
 16 
     | 
    
         
            +
                    end 
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
                  
         
     | 
| 
      
 19 
     | 
    
         
            +
                  def remote_check_required?
         
     | 
| 
      
 20 
     | 
    
         
            +
                    if self.uid && self.session_token && self.recheck
         
     | 
| 
      
 21 
     | 
    
         
            +
                      return (self.recheck <= Time.now)
         
     | 
| 
      
 22 
     | 
    
         
            +
                    end
         
     | 
| 
      
 23 
     | 
    
         
            +
                    return true
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
                  
         
     | 
| 
      
 26 
     | 
    
         
            +
                  # Check remote maestrano session and update the
         
     | 
| 
      
 27 
     | 
    
         
            +
                  # recheck attribute if the session is still valid
         
     | 
| 
      
 28 
     | 
    
         
            +
                  # Return true if the session is still valid and
         
     | 
| 
      
 29 
     | 
    
         
            +
                  # false otherwise
         
     | 
| 
      
 30 
     | 
    
         
            +
                  def perform_remote_check
         
     | 
| 
      
 31 
     | 
    
         
            +
                    # Get remote session info
         
     | 
| 
      
 32 
     | 
    
         
            +
                    url = Maestrano::SSO.session_check_url(self.uid, self.session_token)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 34 
     | 
    
         
            +
                      response = RestClient.get(url)
         
     | 
| 
      
 35 
     | 
    
         
            +
                      response = JSON.parse(response)
         
     | 
| 
      
 36 
     | 
    
         
            +
                    rescue Exception => e
         
     | 
| 
      
 37 
     | 
    
         
            +
                      response = {}
         
     | 
| 
      
 38 
     | 
    
         
            +
                    end
         
     | 
| 
      
 39 
     | 
    
         
            +
                    
         
     | 
| 
      
 40 
     | 
    
         
            +
                    # Process response
         
     | 
| 
      
 41 
     | 
    
         
            +
                    if response['valid'] && response['recheck']
         
     | 
| 
      
 42 
     | 
    
         
            +
                      self.recheck = Time.iso8601(response['recheck'])
         
     | 
| 
      
 43 
     | 
    
         
            +
                      return true
         
     | 
| 
      
 44 
     | 
    
         
            +
                    end
         
     | 
| 
      
 45 
     | 
    
         
            +
                    
         
     | 
| 
      
 46 
     | 
    
         
            +
                    return false
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
                  
         
     | 
| 
      
 49 
     | 
    
         
            +
                  def valid?
         
     | 
| 
      
 50 
     | 
    
         
            +
                    if self.remote_check_required?
         
     | 
| 
      
 51 
     | 
    
         
            +
                      if perform_remote_check
         
     | 
| 
      
 52 
     | 
    
         
            +
                        self.session[:mno_session_recheck] = self.recheck.utc.iso8601
         
     | 
| 
      
 53 
     | 
    
         
            +
                        return true
         
     | 
| 
      
 54 
     | 
    
         
            +
                      else
         
     | 
| 
      
 55 
     | 
    
         
            +
                        return false
         
     | 
| 
      
 56 
     | 
    
         
            +
                      end
         
     | 
| 
      
 57 
     | 
    
         
            +
                    end
         
     | 
| 
      
 58 
     | 
    
         
            +
                    return true
         
     | 
| 
      
 59 
     | 
    
         
            +
                  end
         
     | 
| 
      
 60 
     | 
    
         
            +
                  
         
     | 
| 
      
 61 
     | 
    
         
            +
                end
         
     | 
| 
      
 62 
     | 
    
         
            +
              end
         
     | 
| 
      
 63 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,34 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Maestrano
         
     | 
| 
      
 2 
     | 
    
         
            +
              module SSO
         
     | 
| 
      
 3 
     | 
    
         
            +
                module User
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def find_for_maestrano_auth(auth)
         
     | 
| 
      
 5 
     | 
    
         
            +
                    # E.g with Rails
         
     | 
| 
      
 6 
     | 
    
         
            +
                    # where(auth.slice(:provider, :uid)).first_or_create do |user|
         
     | 
| 
      
 7 
     | 
    
         
            +
                    #   user.provider = auth[:provider]
         
     | 
| 
      
 8 
     | 
    
         
            +
                    #   user.uid = auth[:uid]
         
     | 
| 
      
 9 
     | 
    
         
            +
                    #   user.email = auth[:info][:email]
         
     | 
| 
      
 10 
     | 
    
         
            +
                    #   user.name = auth[:info][:first_name]
         
     | 
| 
      
 11 
     | 
    
         
            +
                    #   user.surname = auth[:info][:last_name]
         
     | 
| 
      
 12 
     | 
    
         
            +
                    #   user.country = auth[:info][:country]
         
     | 
| 
      
 13 
     | 
    
         
            +
                    #   user.company = auth[:info][:company_name]
         
     | 
| 
      
 14 
     | 
    
         
            +
                    # end
         
     | 
| 
      
 15 
     | 
    
         
            +
                    raise NoMethodError, "You need to override find_for_maestrano_auth in your #{self.class.name} model"
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
                  
         
     | 
| 
      
 18 
     | 
    
         
            +
                  # Check whether the user is a maestrano one
         
     | 
| 
      
 19 
     | 
    
         
            +
                  def maestrano?
         
     | 
| 
      
 20 
     | 
    
         
            +
                    if self.respond_to?(:provider)
         
     | 
| 
      
 21 
     | 
    
         
            +
                      return self.provider.to_s == 'maestrano'
         
     | 
| 
      
 22 
     | 
    
         
            +
                    else
         
     | 
| 
      
 23 
     | 
    
         
            +
                      raise NoMethodError, "You need to override maestrano? in your #{self.class.name} model"
         
     | 
| 
      
 24 
     | 
    
         
            +
                    end
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
                  
         
     | 
| 
      
 27 
     | 
    
         
            +
                  # Check whether the SSO session is still valid
         
     | 
| 
      
 28 
     | 
    
         
            +
                  # or not
         
     | 
| 
      
 29 
     | 
    
         
            +
                  def maestrano_session_valid?(session)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    Maestrano::SSO::Session.new(session).valid?
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,170 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # The contents of this file are subject to the terms
         
     | 
| 
      
 2 
     | 
    
         
            +
            # of the Common Development and Distribution License
         
     | 
| 
      
 3 
     | 
    
         
            +
            # (the License). You may not use this file except in
         
     | 
| 
      
 4 
     | 
    
         
            +
            # compliance with the License.
         
     | 
| 
      
 5 
     | 
    
         
            +
            #
         
     | 
| 
      
 6 
     | 
    
         
            +
            # You can obtain a copy of the License at
         
     | 
| 
      
 7 
     | 
    
         
            +
            # https://opensso.dev.java.net/public/CDDLv1.0.html or
         
     | 
| 
      
 8 
     | 
    
         
            +
            # opensso/legal/CDDLv1.0.txt
         
     | 
| 
      
 9 
     | 
    
         
            +
            # See the License for the specific language governing
         
     | 
| 
      
 10 
     | 
    
         
            +
            # permission and limitations under the License.
         
     | 
| 
      
 11 
     | 
    
         
            +
            #
         
     | 
| 
      
 12 
     | 
    
         
            +
            # When distributing Covered Code, include this CDDL
         
     | 
| 
      
 13 
     | 
    
         
            +
            # Header Notice in each file and include the License file
         
     | 
| 
      
 14 
     | 
    
         
            +
            # at opensso/legal/CDDLv1.0.txt.
         
     | 
| 
      
 15 
     | 
    
         
            +
            # If applicable, add the following below the CDDL Header,
         
     | 
| 
      
 16 
     | 
    
         
            +
            # with the fields enclosed by brackets [] replaced by
         
     | 
| 
      
 17 
     | 
    
         
            +
            # your own identifying information:
         
     | 
| 
      
 18 
     | 
    
         
            +
            # "Portions Copyrighted [year] [name of copyright owner]"
         
     | 
| 
      
 19 
     | 
    
         
            +
            #
         
     | 
| 
      
 20 
     | 
    
         
            +
            # $Id: xml_sec.rb,v 1.6 2007/10/24 00:28:41 todddd Exp $
         
     | 
| 
      
 21 
     | 
    
         
            +
            #
         
     | 
| 
      
 22 
     | 
    
         
            +
            # Copyright 2007 Sun Microsystems Inc. All Rights Reserved
         
     | 
| 
      
 23 
     | 
    
         
            +
            # Portions Copyrighted 2007 Todd W Saxton.
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 26 
     | 
    
         
            +
            require "rexml/document"
         
     | 
| 
      
 27 
     | 
    
         
            +
            require "rexml/xpath"
         
     | 
| 
      
 28 
     | 
    
         
            +
            require "openssl"
         
     | 
| 
      
 29 
     | 
    
         
            +
            require 'nokogiri'
         
     | 
| 
      
 30 
     | 
    
         
            +
            require "digest/sha1"
         
     | 
| 
      
 31 
     | 
    
         
            +
            require "digest/sha2"
         
     | 
| 
      
 32 
     | 
    
         
            +
            require "maestrano/saml/validation_error"
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            module Maestrano
         
     | 
| 
      
 35 
     | 
    
         
            +
              module XMLSecurity
         
     | 
| 
      
 36 
     | 
    
         
            +
                class SignedDocument < REXML::Document
         
     | 
| 
      
 37 
     | 
    
         
            +
                  C14N = "http://www.w3.org/2001/10/xml-exc-c14n#"
         
     | 
| 
      
 38 
     | 
    
         
            +
                  DSIG = "http://www.w3.org/2000/09/xmldsig#"
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  attr_accessor :signed_element_id
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                  def initialize(response)
         
     | 
| 
      
 43 
     | 
    
         
            +
                    super(response)
         
     | 
| 
      
 44 
     | 
    
         
            +
                    extract_signed_element_id
         
     | 
| 
      
 45 
     | 
    
         
            +
                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                  def validate_document(idp_cert_fingerprint, soft = true)
         
     | 
| 
      
 48 
     | 
    
         
            +
                    # get cert from response
         
     | 
| 
      
 49 
     | 
    
         
            +
                    cert_element = REXML::XPath.first(self, "//ds:X509Certificate", { "ds"=>DSIG })
         
     | 
| 
      
 50 
     | 
    
         
            +
                    raise Maestrano::Saml::ValidationError.new("Certificate element missing in response (ds:X509Certificate)") unless cert_element
         
     | 
| 
      
 51 
     | 
    
         
            +
                    base64_cert  = cert_element.text
         
     | 
| 
      
 52 
     | 
    
         
            +
                    cert_text    = Base64.decode64(base64_cert)
         
     | 
| 
      
 53 
     | 
    
         
            +
                    cert         = OpenSSL::X509::Certificate.new(cert_text)
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                    # check cert matches registered idp cert
         
     | 
| 
      
 56 
     | 
    
         
            +
                    fingerprint = Digest::SHA1.hexdigest(cert.to_der)
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                    if fingerprint != idp_cert_fingerprint.gsub(/[^a-zA-Z0-9]/,"").downcase
         
     | 
| 
      
 59 
     | 
    
         
            +
                      return soft ? false : (raise Maestrano::Saml::ValidationError.new("Fingerprint mismatch"))
         
     | 
| 
      
 60 
     | 
    
         
            +
                    end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                    validate_signature(base64_cert, soft)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                  def validate_signature(base64_cert, soft = true)
         
     | 
| 
      
 66 
     | 
    
         
            +
                    # validate references
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                    # check for inclusive namespaces
         
     | 
| 
      
 69 
     | 
    
         
            +
                    inclusive_namespaces = extract_inclusive_namespaces
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                    document = Nokogiri.parse(self.to_s)
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                    # create a working copy so we don't modify the original
         
     | 
| 
      
 74 
     | 
    
         
            +
                    @working_copy ||= REXML::Document.new(self.to_s).root
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                    # store and remove signature node
         
     | 
| 
      
 77 
     | 
    
         
            +
                    @sig_element ||= begin
         
     | 
| 
      
 78 
     | 
    
         
            +
                      element = REXML::XPath.first(@working_copy, "//ds:Signature", {"ds"=>DSIG})
         
     | 
| 
      
 79 
     | 
    
         
            +
                      element.remove
         
     | 
| 
      
 80 
     | 
    
         
            +
                    end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                    # verify signature
         
     | 
| 
      
 84 
     | 
    
         
            +
                    signed_info_element     = REXML::XPath.first(@sig_element, "//ds:SignedInfo", {"ds"=>DSIG})
         
     | 
| 
      
 85 
     | 
    
         
            +
                    noko_sig_element = document.at_xpath('//ds:Signature', 'ds' => DSIG)
         
     | 
| 
      
 86 
     | 
    
         
            +
                    noko_signed_info_element = noko_sig_element.at_xpath('./ds:SignedInfo', 'ds' => DSIG)
         
     | 
| 
      
 87 
     | 
    
         
            +
                    canon_algorithm = canon_algorithm REXML::XPath.first(@sig_element, '//ds:CanonicalizationMethod', 'ds' => DSIG)
         
     | 
| 
      
 88 
     | 
    
         
            +
                    canon_string = noko_signed_info_element.canonicalize(canon_algorithm)
         
     | 
| 
      
 89 
     | 
    
         
            +
                    noko_sig_element.remove
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                    # check digests
         
     | 
| 
      
 92 
     | 
    
         
            +
                    REXML::XPath.each(@sig_element, "//ds:Reference", {"ds"=>DSIG}) do |ref|
         
     | 
| 
      
 93 
     | 
    
         
            +
                      uri                           = ref.attributes.get_attribute("URI").value
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                      hashed_element                = document.at_xpath("//*[@ID='#{uri[1..-1]}']")
         
     | 
| 
      
 96 
     | 
    
         
            +
                      canon_algorithm               = canon_algorithm REXML::XPath.first(ref, '//ds:CanonicalizationMethod', 'ds' => DSIG)
         
     | 
| 
      
 97 
     | 
    
         
            +
                      canon_hashed_element          = hashed_element.canonicalize(canon_algorithm, inclusive_namespaces)
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                      digest_algorithm              = algorithm(REXML::XPath.first(ref, "//ds:DigestMethod"))
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                      hash                          = digest_algorithm.digest(canon_hashed_element)
         
     | 
| 
      
 102 
     | 
    
         
            +
                      digest_value                  = Base64.decode64(REXML::XPath.first(ref, "//ds:DigestValue", {"ds"=>DSIG}).text)
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
                      unless digests_match?(hash, digest_value)
         
     | 
| 
      
 105 
     | 
    
         
            +
                        return soft ? false : (raise Maestrano::Saml::ValidationError.new("Digest mismatch"))
         
     | 
| 
      
 106 
     | 
    
         
            +
                      end
         
     | 
| 
      
 107 
     | 
    
         
            +
                    end
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
                    base64_signature        = REXML::XPath.first(@sig_element, "//ds:SignatureValue", {"ds"=>DSIG}).text
         
     | 
| 
      
 110 
     | 
    
         
            +
                    signature               = Base64.decode64(base64_signature)
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                    # get certificate object
         
     | 
| 
      
 113 
     | 
    
         
            +
                    cert_text               = Base64.decode64(base64_cert)
         
     | 
| 
      
 114 
     | 
    
         
            +
                    cert                    = OpenSSL::X509::Certificate.new(cert_text)
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                    # signature method
         
     | 
| 
      
 117 
     | 
    
         
            +
                    signature_algorithm     = algorithm(REXML::XPath.first(signed_info_element, "//ds:SignatureMethod", {"ds"=>DSIG}))
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
                    unless cert.public_key.verify(signature_algorithm.new, signature, canon_string)
         
     | 
| 
      
 120 
     | 
    
         
            +
                      return soft ? false : (raise Maestrano::Saml::ValidationError.new("Key validation error"))
         
     | 
| 
      
 121 
     | 
    
         
            +
                    end
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
                    return true
         
     | 
| 
      
 124 
     | 
    
         
            +
                  end
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                  private
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
      
 128 
     | 
    
         
            +
                  def digests_match?(hash, digest_value)
         
     | 
| 
      
 129 
     | 
    
         
            +
                    hash == digest_value
         
     | 
| 
      
 130 
     | 
    
         
            +
                  end
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
                  def extract_signed_element_id
         
     | 
| 
      
 133 
     | 
    
         
            +
                    reference_element       = REXML::XPath.first(self, "//ds:Signature/ds:SignedInfo/ds:Reference", {"ds"=>DSIG})
         
     | 
| 
      
 134 
     | 
    
         
            +
                    self.signed_element_id  = reference_element.attribute("URI").value[1..-1] unless reference_element.nil?
         
     | 
| 
      
 135 
     | 
    
         
            +
                  end
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
                  def canon_algorithm(element)
         
     | 
| 
      
 138 
     | 
    
         
            +
                    algorithm = element.attribute('Algorithm').value if element
         
     | 
| 
      
 139 
     | 
    
         
            +
                    case algorithm
         
     | 
| 
      
 140 
     | 
    
         
            +
                      when "http://www.w3.org/2001/10/xml-exc-c14n#"         then Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0
         
     | 
| 
      
 141 
     | 
    
         
            +
                      when "http://www.w3.org/TR/2001/REC-xml-c14n-20010315" then Nokogiri::XML::XML_C14N_1_0
         
     | 
| 
      
 142 
     | 
    
         
            +
                      when "http://www.w3.org/2006/12/xml-c14n11"            then Nokogiri::XML::XML_C14N_1_1
         
     | 
| 
      
 143 
     | 
    
         
            +
                      else                                                        Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0
         
     | 
| 
      
 144 
     | 
    
         
            +
                    end
         
     | 
| 
      
 145 
     | 
    
         
            +
                  end
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                  def algorithm(element)
         
     | 
| 
      
 148 
     | 
    
         
            +
                    algorithm = element.attribute("Algorithm").value if element
         
     | 
| 
      
 149 
     | 
    
         
            +
                    algorithm = algorithm && algorithm =~ /sha(.*?)$/i && $1.to_i
         
     | 
| 
      
 150 
     | 
    
         
            +
                    case algorithm
         
     | 
| 
      
 151 
     | 
    
         
            +
                    when 256 then OpenSSL::Digest::SHA256
         
     | 
| 
      
 152 
     | 
    
         
            +
                    when 384 then OpenSSL::Digest::SHA384
         
     | 
| 
      
 153 
     | 
    
         
            +
                    when 512 then OpenSSL::Digest::SHA512
         
     | 
| 
      
 154 
     | 
    
         
            +
                    else
         
     | 
| 
      
 155 
     | 
    
         
            +
                      OpenSSL::Digest::SHA1
         
     | 
| 
      
 156 
     | 
    
         
            +
                    end
         
     | 
| 
      
 157 
     | 
    
         
            +
                  end
         
     | 
| 
      
 158 
     | 
    
         
            +
             
     | 
| 
      
 159 
     | 
    
         
            +
                  def extract_inclusive_namespaces
         
     | 
| 
      
 160 
     | 
    
         
            +
                    if element = REXML::XPath.first(self, "//ec:InclusiveNamespaces", { "ec" => C14N })
         
     | 
| 
      
 161 
     | 
    
         
            +
                      prefix_list = element.attributes.get_attribute("PrefixList").value
         
     | 
| 
      
 162 
     | 
    
         
            +
                      prefix_list.split(" ")
         
     | 
| 
      
 163 
     | 
    
         
            +
                    else
         
     | 
| 
      
 164 
     | 
    
         
            +
                      []
         
     | 
| 
      
 165 
     | 
    
         
            +
                    end
         
     | 
| 
      
 166 
     | 
    
         
            +
                  end
         
     | 
| 
      
 167 
     | 
    
         
            +
             
     | 
| 
      
 168 
     | 
    
         
            +
                end
         
     | 
| 
      
 169 
     | 
    
         
            +
              end
         
     | 
| 
      
 170 
     | 
    
         
            +
            end
         
     |