saml2 3.2.4 → 3.3.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 05f37a8ab729b5a78b6b76c430ae6613d5852613b45980721510e60925b39872
4
- data.tar.gz: 1e1ea950995d3deefa465c0fdb2c45c796327bf739633ec2e9b1d977931ee116
3
+ metadata.gz: 771858fe6a969b67349b77e75471ae2e3cf39f63bddf09a4944d9edaa022e870
4
+ data.tar.gz: 85b835224adb9a15269d5b6d3d62cc7a3320cd391c714445e7399e51dadccedb
5
5
  SHA512:
6
- metadata.gz: 3f3f9d16794991653ebd7c779e5f325b4d0f48a94d90d08f225b82329ec448f09fb495a0028ab3b3b13bb7d9a797fc0c8a4ec0df8630822527e632303d54f408
7
- data.tar.gz: 4e025a411a4dea50efa1377c3e2b09c1aa34f52db3ddb1e1e146041835dd392e9945e831751cc1f0b749c19e3c792af630d7b27dcbaaea3fe5544d8c15be4ccd
6
+ metadata.gz: 2837de4133371963522b8d159d58bbebed7c4bbd8feef331d2445281a40df95a818e63607c4095e2d8a93141f2288a5697f2c00a789b1f8316b45da092ba83a3
7
+ data.tar.gz: de08845f21f153d09e72644dd1dce422d198e492d974fda7f63fd26380e57ca3d61ec07a80ecf3686849a95ea985a5e09fde2981dd29ac043c9f1afdc4824ae4
@@ -4,27 +4,45 @@ require "saml2/base"
4
4
 
5
5
  module SAML2
6
6
  class AuthnStatement < Base
7
+ # @see https://docs.oasis-open.org/security/saml/v2.0/saml-authn-context-2.0-os.pdf
7
8
  module Classes
8
- INTERNET_PROTOCOL =
9
- "urn:oasis:names:tc:SAML:2.0:ac:classes:InternetProtocol" # IP address
10
- INTERNET_PROTOCOL_PASSWORD =
11
- "urn:oasis:names:tc:SAML:2.0:ac:classes:InternetProtocolPassword" # IP address, as well as username/password
12
- KERBEROS =
13
- "urn:oasis:names:tc:SAML:2.0:ac:classes:Kerberos"
14
- PASSWORD =
15
- "urn:oasis:names:tc:SAML:2.0:ac:classes:Password" # username/password, NOT over SSL
16
- PASSWORD_PROTECTED_TRANSPORT =
17
- "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport" # username/password over SSL
18
- PREVIOUS_SESSION =
19
- "urn:oasis:names:tc:SAML:2.0:ac:classes:PreviousSession" # remember me
20
- SMARTCARD =
21
- "urn:oasis:names:tc:SAML:2.0:ac:classes:Smartcard"
22
- SMARTCARD_PKI =
23
- "urn:oasis:names:tc:SAML:2.0:ac:classes:SmartcardPKI" # smartcard with a private key on it
24
- TLS_CLIENT =
25
- "urn:oasis:names:tc:SAML:2.0:ac:classes:TLSClient" # SSL client certificate
26
- UNSPECIFIED =
27
- "urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified"
9
+ INTERNET_PROTOCOL = "urn:oasis:names:tc:SAML:2.0:ac:classes:InternetProtocol"
10
+ INTERNET_PROTOCOL_PASSWORD = "urn:oasis:names:tc:SAML:2.0:ac:classes:InternetProtocolPassword"
11
+ KERBEROS = "urn:oasis:names:tc:SAML:2.0:ac:classes:Kerberos"
12
+ MOBILE_ONE_FACTOR_CONTRACT = "urn:oasis:names:tc:SAML:2.0:ac:classes:MobileOneFactorContract"
13
+ MOBILE_ONE_FACTOR_UNREGISTERED = "urn:oasis:names:tc:SAML:2.0:ac:classes:MobileOneFactorUnregistered"
14
+ MOBILE_TWO_FACTOR_CONTRACT = "urn:oasis:names:tc:SAML:2.0:ac:classes:MobileTwoFactorContract"
15
+ MOBILE_TWO_FACTOR_UNREGISTERED = "urn:oasis:names:tc:SAML:2.0:ac:classes:MobileTwoFactorUnregistered"
16
+ PASSWORD = "urn:oasis:names:tc:SAML:2.0:ac:classes:Password"
17
+ PASSWORD_PROTECTED_TRANSPORT = "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"
18
+ PGP = "urn:oasis:names:tc:SAML:2.0:ac:classes:PGP"
19
+ PREVIOUS_SESSION = "urn:oasis:names:tc:SAML:2.0:ac:classes:PreviousSession"
20
+ SMARTCARD = "urn:oasis:names:tc:SAML:2.0:ac:classes:Smartcard"
21
+ SMARTCARD_PKI = "urn:oasis:names:tc:SAML:2.0:ac:classes:SmartcardPKI"
22
+ SOFTWARE_PKI = "urn:oasis:names:tc:SAML:2.0:ac:classes:SoftwarePKI"
23
+ SPKI = "urn:oasis:names:tc:SAML:2.0:ac:classes:SPKI"
24
+ SECURE_REMOTE_PASSWORD = "urn:oasis:names:tc:SAML:2.0:ac:classes:SecureRemotePassword"
25
+ TELEPHONY = "urn:oasis:names:tc:SAML:2.0:ac:classes:Telephony"
26
+ TELEPHONY_AUTHENTICATED = "urn:oasis:names:tc:SAML:2.0:ac:classes:AuthenticatedTelephony"
27
+ TELEPHONHY_NOMAD = "urn:oasis:names:tc:SAML:2.0:ac:classes:NomadTelephony"
28
+ TELEPHONY_PERSONALIZED = "urn:oasis:names:tc:SAML:2.0:ac:classes:PersonalTelephony"
29
+ TIME_SYNC_TOKEN = "urn:oasis:names:tc:SAML:2.0:ac:classes:TimeSyncToken"
30
+ TLS_CLIENT = "urn:oasis:names:tc:SAML:2.0:ac:classes:TLSClient"
31
+ X509 = "urn:oasis:names:tc:SAML:2.0:ac:classes:X509"
32
+ XMLDSIG = "urn:oasis:names:tc:SAML:2.0:ac:classes:XMLDSig"
33
+ UNSPECIFIED = "urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified"
34
+
35
+ # @see https://refeds.org/profile/mfa
36
+ REFEDS_MFA = "https://refeds.org/profile/mfa"
37
+ # @see https://refeds.org/profile/sfa
38
+ REFEDS_SFA = "https://refeds.org/profile/sfa"
39
+
40
+ # @see https://learn.microsoft.com/en-us/entra/identity/authentication/how-to-mfa-expected-inbound-assertions
41
+ MICROSOFT_MULTIPLE_AUTHN = "http://schemas.microsoft.com/claims/multipleauthn"
42
+ # @see https://learn.microsoft.com/en-us/entra/identity/authentication/how-to-mfa-expected-inbound-assertions
43
+ MICROSOFT_WIA_OR_MULTI_AUTHN = "http://schemas.microsoft.com/claims/wiaormultiauthn"
44
+ # @see https://learn.microsoft.com/en-us/entra/identity-platform/single-sign-on-saml-protocol#requestedauthncontext
45
+ MICROSOFT_WINDOWS = "urn:federation:authentication:windows"
28
46
  end
29
47
 
30
48
  # @return [Time]
data/lib/saml2/status.rb CHANGED
@@ -7,24 +7,74 @@ module SAML2
7
7
  SUCCESS = "urn:oasis:names:tc:SAML:2.0:status:Success"
8
8
  REQUESTER = "urn:oasis:names:tc:SAML:2.0:status:Requester"
9
9
  RESPONDER = "urn:oasis:names:tc:SAML:2.0:status:Responder"
10
+ VERSION_MISMATCH = "urn:oasis:names:tc:SAML:2.0:status:VersionMismatch"
10
11
 
12
+ AUTHN_FAILED = "urn:oasis:names:tc:SAML:2.0:status:AuthnFailed"
13
+ INVALID_ATTR_NAME_OR_VALUE = "urn:oasis:names:tc:SAML:2.0:status:InvalidAttrNameOrValue"
14
+ INVALID_NAME_ID_POLICY = "urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy"
15
+ NO_AUTHN_CONTEXT = "urn:oasis:names:tc:SAML:2.0:status:NoAuthnContext"
16
+ NO_AVAILABLE_IDP = "urn:oasis:names:tc:SAML:2.0:status:NoAvailableIDP"
17
+ NO_PASSIVE = "urn:oasis:names:tc:SAML:2.0:status:NoPassive"
18
+ NO_SUPPORTED_IDP = "urn:oasis:names:tc:SAML:2.0:status:NoSupportedIDP"
19
+ PARTIAL_LOGOUT = "urn:oasis:names:tc:SAML:2.0:status:PartialLogout"
20
+ PROXY_COUNT_EXCEEDED = "urn:oasis:names:tc:SAML:2.0:status:ProxyCountExceeded"
21
+ REQUEST_DENIED = "urn:oasis:names:tc:SAML:2.0:status:RequestDenied"
22
+ REQUEST_UNSUPPORTED = "urn:oasis:names:tc:SAML:2.0:status:RequestUnsupported"
23
+ REQUEST_VERSION_DEPRECATED = "urn:oasis:names:tc:SAML:2.0:status:RequestVersionDeprecated"
24
+ REQUEST_VERSION_TOO_HIGH = "urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooHigh"
25
+ REQUEST_VERSION_TOO_LOW = "urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooLow"
26
+ RESOURCE_NOT_RECOGNIZED = "urn:oasis:names:tc:SAML:2.0:status:ResourceNotRecognized"
27
+ TOO_MANY_RESPONSES = "urn:oasis:names:tc:SAML::2.0:status:TooManyResponses"
28
+ UNKNOWN_ATTR_PROFILE = "urn:oasis:names:tc:SAML:2.0:status:UnknownAttrProfile"
29
+ UNKNOWN_PRINCIPAL = "urn:oasis:names:tc:SAML:2.0:status:UnknownPrincipal"
30
+ UNSUPPORTED_BINDING = "urn:oasis:names:tc:SAML:2.0:status:UnsupportedBinding"
31
+
32
+ TOP_LEVEL_STATUS_CODES = [SUCCESS, REQUESTER, RESPONDER, VERSION_MISMATCH].freeze
33
+
34
+ # @return [Array<String>]
35
+ attr_reader :codes
11
36
  # @return [String]
12
- attr_accessor :code, :message
37
+ attr_accessor :message, :detail
13
38
 
14
39
  # @param code [String]
15
40
  # @param message [String, nil]
16
- def initialize(code = SUCCESS, message = nil)
41
+ def initialize(code = SUCCESS, message = nil, detail = nil)
17
42
  super()
18
- @code = code
43
+ self.codes = code
19
44
  @message = message
45
+ @detail = detail
20
46
  end
21
47
 
22
48
  # (see Base#from_xml)
23
49
  def from_xml(node)
24
50
  super
25
- self.code = node.at_xpath("samlp:StatusCode", Namespaces::ALL)["Value"]
26
- self.message = load_string_array(xml, "samlp:StatusMessage")
51
+
52
+ @codes.clear
53
+ code_node = node
54
+
55
+ loop do
56
+ code_node = code_node.at_xpath("samlp:StatusCode", Namespaces::ALL)
57
+ break unless code_node
58
+
59
+ codes << code_node["Value"]
60
+ end
61
+ self.message = xml.at_xpath("samlp:StatusMessage", Namespaces::ALL)&.content&.strip
62
+ self.detail = xml.at_xpath("samlp:StatusDetail", Namespaces::ALL)&.content&.strip
63
+ end
64
+
65
+ def code
66
+ codes.first
67
+ end
68
+
69
+ def codes=(value)
70
+ codes = Array.wrap(value)
71
+ unless TOP_LEVEL_STATUS_CODES.include?(codes.first)
72
+ raise ArgumentError, "Invalid top level status code #{codes.first.inspect}"
73
+ end
74
+
75
+ @codes = codes
27
76
  end
77
+ alias_method :code=, :codes=
28
78
 
29
79
  def success?
30
80
  code == SUCCESS
@@ -33,10 +83,20 @@ module SAML2
33
83
  # (see Base#build)
34
84
  def build(builder)
35
85
  builder["samlp"].Status do |status|
36
- status["samlp"].StatusCode(Value: code)
37
- Array(message).each do |m|
38
- status["samlp"].StatusMessage(m)
39
- end
86
+ build_code(status, codes, 0)
87
+
88
+ status["samlp"].StatusMessage(message) if message
89
+ status["samlp"].StatusDetail(detail) if detail
90
+ end
91
+ end
92
+
93
+ private
94
+
95
+ def build_code(builder, codes, idx)
96
+ return if idx >= codes.length
97
+
98
+ builder["samlp"].StatusCode(Value: codes[idx]) do |code_builder|
99
+ build_code(code_builder, codes, idx + 1)
40
100
  end
41
101
  end
42
102
  end
data/lib/saml2/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SAML2
4
- VERSION = "3.2.4"
4
+ VERSION = "3.3.1"
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: saml2
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.4
4
+ version: 3.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cody Cutrer
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-10-13 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: activesupport
@@ -158,7 +158,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
158
158
  - !ruby/object:Gem::Version
159
159
  version: '0'
160
160
  requirements: []
161
- rubygems_version: 3.6.3
161
+ rubygems_version: 3.6.9
162
162
  specification_version: 4
163
163
  summary: SAML 2.0 Library
164
164
  test_files: []