msidp-endpoint 0.1.1 → 0.2.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 +4 -4
- data/exe/msidp-cert2assertion +29 -0
- data/lib/msidp/certificate_credential.rb +89 -0
- data/lib/msidp/endpoint/version.rb +1 -1
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 37385ee2c6bd0f32d4cc2a176e7140ba05a1f756a97e5539c963dcb1b4a9c075
|
4
|
+
data.tar.gz: d586b59889dbe8b58f4aaeba41abc5dc52fbbd07ed06367607c0b2bd703b603a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7c7cdd5a0bad6a7da2ce4f43c63683c8b9d81308053490bdd1cc842195f6f1d7bc2dc02b1d65c6bb1009fc2ed734444c8e3007dcb9b6793edc6a51c5796b80f3
|
7
|
+
data.tar.gz: 7efc055c1962d6a7eeda5742cb8845303f4ea728ec30fd103d291748a603c99d7412843d7eb832527c564631a3e585cee18fb8fbe98105c94de8f899f1351309
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'msidp/certificate_credential'
|
5
|
+
|
6
|
+
if ARGV.length < 4
|
7
|
+
progname = File.basename($PROGRAM_NAME)
|
8
|
+
warn <<~USAGE
|
9
|
+
Compute a client assetion for a certificate pair.
|
10
|
+
Usage:
|
11
|
+
#{progname} certificate_file private_key_file tenant_id client_id
|
12
|
+
certificate_file: public certificate file
|
13
|
+
private_key_file: private key file
|
14
|
+
tenant_id: tenant ID in GUID or domain-name format
|
15
|
+
client_id: applicaiton (client) ID
|
16
|
+
USAGE
|
17
|
+
exit 64
|
18
|
+
end
|
19
|
+
|
20
|
+
certificate, private_key, tenant_id, client_id = ARGV
|
21
|
+
|
22
|
+
cert = OpenSSL::X509::Certificate.new(File.binread(certificate))
|
23
|
+
key = OpenSSL::PKey::RSA.new(File.binread(private_key))
|
24
|
+
|
25
|
+
cred = MSIDP::CertificateCredential.new(
|
26
|
+
cert, key, tenant_id: tenant_id, client_id: client_id
|
27
|
+
)
|
28
|
+
|
29
|
+
puts cred.assertion
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'openssl'
|
4
|
+
require 'base64'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
module MSIDP
|
8
|
+
# Certificate credential for application authentication
|
9
|
+
class CertificateCredential
|
10
|
+
# @return [String] tenant a directory tenant in GUID or domain-name format.
|
11
|
+
attr_accessor :tenant
|
12
|
+
# @return [String] client_id the assigned applicaiton (client) ID.
|
13
|
+
attr_accessor :client_id
|
14
|
+
|
15
|
+
# Initialize an instance
|
16
|
+
#
|
17
|
+
# @param [OpenSSL::X509::Certificate] cert a certificate.
|
18
|
+
# @param [OpenSSL::PKey] cert the private key paired with the certificate.
|
19
|
+
# @param [String] tenant a directory tenant in GUID or domain-name format.
|
20
|
+
# @param [String] client_id the assigned applicaiton (client) ID.
|
21
|
+
def initialize(cert, key, tenant:, client_id:)
|
22
|
+
@cert = cert
|
23
|
+
@key = key
|
24
|
+
@tenant = tenant
|
25
|
+
@client_id = client_id
|
26
|
+
end
|
27
|
+
|
28
|
+
# Computes the JWT assertion.
|
29
|
+
#
|
30
|
+
# @return [String] JWT assertion string.
|
31
|
+
def assertion
|
32
|
+
header_base64 = base64url_encode(header)
|
33
|
+
payload_base64 = base64url_encode(payload)
|
34
|
+
signature = @key.sign('sha256', "#{header_base64}.#{payload_base64}")
|
35
|
+
sign_base64 = base64url_encode(signature)
|
36
|
+
"#{header_base64}.#{payload_base64}.#{sign_base64}"
|
37
|
+
end
|
38
|
+
|
39
|
+
# JOSE header of the JWT.
|
40
|
+
#
|
41
|
+
# @return [String] JSON string of the JOSE header.
|
42
|
+
def header
|
43
|
+
digest = OpenSSL::Digest::SHA1.digest(@cert.to_der)
|
44
|
+
x5t = Base64.urlsafe_encode64(digest)
|
45
|
+
header = { alg: 'RS256', typ: 'JWT', x5t: x5t.to_s }
|
46
|
+
JSON.dump(header)
|
47
|
+
end
|
48
|
+
|
49
|
+
# JWS payload of the JWT claim.
|
50
|
+
#
|
51
|
+
# @return [String] JSON string of the JWS payload.
|
52
|
+
def payload
|
53
|
+
not_after = @cert.not_after.to_i
|
54
|
+
not_before = @cert.not_before.to_i
|
55
|
+
jti = make_jwt_id
|
56
|
+
payload = {
|
57
|
+
aud: "https://login.microsoftonline.com/#{tenant}/v2.0",
|
58
|
+
exp: not_after, iss: client_id, jti: jti,
|
59
|
+
nbf: not_after, sub: client_id, iat: not_before
|
60
|
+
}
|
61
|
+
JSON.dump(payload)
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def base64url_encode(data)
|
67
|
+
Base64.urlsafe_encode64(data, padding: false)
|
68
|
+
end
|
69
|
+
|
70
|
+
def make_jwt_id
|
71
|
+
data = @cert.to_der
|
72
|
+
data << tenant
|
73
|
+
data << client_id
|
74
|
+
sha1hash_uuid(OpenSSL::Digest::SHA1.digest(data))
|
75
|
+
end
|
76
|
+
|
77
|
+
# rubocop:disable Style/FormatStringToken
|
78
|
+
def sha1hash_uuid(hash)
|
79
|
+
bytes = hash.bytes[0..15]
|
80
|
+
bytes[6] = bytes[6] & 0x0F | 0x50
|
81
|
+
bytes[8] = bytes[6] & 0x3F | 0x80
|
82
|
+
format(
|
83
|
+
'%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x',
|
84
|
+
*bytes
|
85
|
+
)
|
86
|
+
end
|
87
|
+
# rubocop:enable Style/FormatStringToken
|
88
|
+
end
|
89
|
+
end
|
metadata
CHANGED
@@ -1,25 +1,28 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: msidp-endpoint
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- SHIMAYOSHI, Takao
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-03-07 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Simple class library for Microsoft Identity Platform endpoints.
|
14
14
|
email:
|
15
15
|
- simayosi@cc.kyushu-u.ac.jp
|
16
|
-
executables:
|
16
|
+
executables:
|
17
|
+
- msidp-cert2assertion
|
17
18
|
extensions: []
|
18
19
|
extra_rdoc_files: []
|
19
20
|
files:
|
20
21
|
- LICENSE.txt
|
21
22
|
- README.md
|
23
|
+
- exe/msidp-cert2assertion
|
22
24
|
- lib/msidp/access_token.rb
|
25
|
+
- lib/msidp/certificate_credential.rb
|
23
26
|
- lib/msidp/endpoint.rb
|
24
27
|
- lib/msidp/endpoint/version.rb
|
25
28
|
- lib/msidp/error.rb
|