• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

malach-it / boruta_auth / 954161a5b397cc94069ec938dc16fcb785e37074-PR-29

18 Jan 2025 10:28PM UTC coverage: 85.651% (-4.3%) from 89.944%
954161a5b397cc94069ec938dc16fcb785e37074-PR-29

Pull #29

github

patatoid
refactor verifiable credentials status tokens
Pull Request #29: Agent credentials PoC

188 of 304 new or added lines in 20 files covered. (61.84%)

3 existing lines in 1 file now uncovered.

1552 of 1812 relevant lines covered (85.65%)

85.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.25
/lib/boruta/adapters/internal/signatures.ex
1
defmodule Boruta.Internal.Signatures do
2
  @behaviour Boruta.Oauth.Signatures
3

4
  defmodule Token do
5
    @moduledoc false
6

7
    use Joken.Config
8

NEW
9
    def token_config, do: %{}
×
10
  end
11

12
  @moduledoc false
13

14
  alias Boruta.Internal.Signatures.SigningKey
15
  alias Boruta.Oauth.Client
16

17
  @signature_algorithms [
18
    ES256: [type: :asymmetric, hash_algorithm: :SHA256, binary_size: 16],
19
    ES384: [type: :asymmetric, hash_algorithm: :SHA384, binary_size: 24],
20
    ES512: [type: :asymmetric, hash_algorithm: :SHA512, binary_size: 32],
21
    RS256: [type: :asymmetric, hash_algorithm: :SHA256, binary_size: 16],
22
    RS384: [type: :asymmetric, hash_algorithm: :SHA384, binary_size: 24],
23
    RS512: [type: :asymmetric, hash_algorithm: :SHA512, binary_size: 32],
24
    HS256: [type: :symmetric, hash_algorithm: :SHA256, binary_size: 16],
25
    HS384: [type: :symmetric, hash_algorithm: :SHA384, binary_size: 24],
26
    HS512: [type: :symmetric, hash_algorithm: :SHA512, binary_size: 32]
27
  ]
28

29
  @spec hash_alg(Client.t()) :: hash_alg :: atom()
30
  def hash_alg(%Client{id_token_signature_alg: signature_alg}),
31
    do: @signature_algorithms[String.to_atom(signature_alg)][:hash_algorithm]
25✔
32

33
  @spec hash_binary_size(Client.t()) :: binary_size :: integer()
34
  def hash_binary_size(%Client{id_token_signature_alg: signature_alg}),
35
    do: @signature_algorithms[String.to_atom(signature_alg)][:binary_size]
25✔
36

37
  @spec hash(string :: String.t(), client :: Client.t()) :: hash :: String.t()
38
  def hash(string, client) do
39
    hash_alg(client)
40
    |> Atom.to_string()
41
    |> String.downcase()
42
    |> String.to_atom()
43
    |> :crypto.hash(string)
44
    |> binary_part(0, hash_binary_size(client))
45
    |> Base.url_encode64(padding: false)
25✔
46
  end
47

48
  @spec id_token_sign(payload :: map(), client :: Client.t()) ::
49
          jwt :: String.t() | {:error, reason :: String.t()}
50
  def id_token_sign(
51
        payload,
52
        %Client{
53
          id_token_signature_alg: signature_alg
54
        } = client
55
      ) do
56
    with {:ok, signing_key} <- get_signing_key(client, :id_token) do
21✔
57
      signer =
21✔
58
        case id_token_signature_type(client) do
59
          :symmetric ->
60
            Joken.Signer.create(signature_alg, signing_key.secret)
3✔
61

62
          :asymmetric ->
63
            Joken.Signer.create(
18✔
64
              signature_alg,
65
              %{"pem" => signing_key.private_key},
18✔
66
              %{
67
                "kid" => signing_key.kid,
18✔
68
                "trust_chain" => signing_key.trust_chain
18✔
69
              }
70
            )
71
        end
72

73
      case Token.encode_and_sign(payload, signer) do
21✔
74
        {:ok, token, _payload} ->
75
          token
21✔
76

NEW
77
        {:error, error} ->
×
78
          {:error, "Could not sign the given payload with client credentials: #{inspect(error)}"}
79
      end
80
    end
81
  end
82

83
  @spec userinfo_sign(payload :: map(), client :: Client.t()) ::
84
          jwt :: String.t() | {:error, reason :: String.t()}
85
  def userinfo_sign(
86
        payload,
87
        %Client{
88
          userinfo_signed_response_alg: signature_alg
89
        } = client
90
      ) do
91
    with {:ok, signing_key} <- get_signing_key(client, :userinfo) do
2✔
92
      signer =
2✔
93
        case userinfo_signature_type(client) do
94
          :symmetric ->
95
            Joken.Signer.create(signature_alg, signing_key.secret)
2✔
96

97
          :asymmetric ->
NEW
98
            Joken.Signer.create(
×
99
              signature_alg,
NEW
100
              %{"pem" => signing_key.private_key},
×
101
              %{
NEW
102
                "kid" => signing_key.kid,
×
NEW
103
                "trust_chain" => signing_key.trust_chain
×
104
              }
105
            )
106
        end
107

108
      case Token.encode_and_sign(payload, signer) do
2✔
109
        {:ok, token, _payload} ->
110
          token
2✔
111

NEW
112
        {:error, error} ->
×
113
          {:error, "Could not sign the given payload with client credentials: #{inspect(error)}"}
114
      end
115
    end
116
  end
117

118
  @spec verifiable_credential_sign(payload :: map(), client :: Client.t(), format :: String.t()) ::
119
          jwt :: String.t() | {:error, reason :: String.t()}
120
  def verifiable_credential_sign(
121
        payload,
122
        %Client{
123
          id_token_signature_alg: signature_alg
124
        } = client,
125
        _format
126
      ) do
127
    with {:ok, signing_key} <- get_signing_key(client, :verifiable_credential) do
10✔
128
      signer =
10✔
129
        case id_token_signature_type(client) do
130
          :symmetric ->
NEW
131
            Joken.Signer.create(signature_alg, signing_key.secret)
×
132

133
          :asymmetric ->
134
            Joken.Signer.create(
10✔
135
              signature_alg,
136
              %{"pem" => signing_key.private_key},
10✔
137
              %{
138
                "typ" => "JWT",
139
                "kid" => signing_key.kid,
10✔
140
                "trust_chain" => signing_key.trust_chain
10✔
141
              }
142
            )
143
        end
144

145
      case Token.encode_and_sign(payload, signer) do
10✔
146
        {:ok, token, _payload} ->
147
          token
10✔
148

NEW
149
        {:error, error} ->
×
150
          {:error, "Could not sign the given payload with client credentials: #{inspect(error)}"}
151
      end
152
    end
153
  end
154

155
  @spec userinfo_signature_type(Client.t()) :: userinfo_token_signature_type :: atom()
156
  def userinfo_signature_type(%Client{userinfo_signed_response_alg: signature_alg}),
157
    do: @signature_algorithms[String.to_atom(signature_alg)][:type]
2✔
158

159
  @spec id_token_signature_type(Client.t()) :: id_token_signature_type :: atom()
160
  def id_token_signature_type(%Client{id_token_signature_alg: signature_alg}),
161
    do: @signature_algorithms[String.to_atom(signature_alg)][:type]
31✔
162

163
  defp get_signing_key(client, :id_token) do
21✔
164
    {:ok,
165
     %SigningKey{
166
       type: :internal,
167
       private_key: client.private_key,
21✔
168
       secret: client.secret,
21✔
169
       kid: client.did || client.id_token_kid || Client.Crypto.kid_from_private_key(client.private_key)
21✔
170
     }}
171
  end
172

173
  defp get_signing_key(client, :userinfo) do
2✔
174
    {:ok,
175
     %SigningKey{
176
       type: :internal,
177
       private_key: client.private_key,
2✔
178
       secret: client.secret,
2✔
179
       kid: client.id
2✔
180
     }}
181
  end
182

183
  defp get_signing_key(client, :verifiable_credential) do
10✔
184
    {:ok,
185
     %SigningKey{
186
       type: :internal,
187
       private_key: client.private_key,
10✔
188
       secret: client.secret,
10✔
189
       kid: client.did || client.id_token_kid || Client.Crypto.kid_from_private_key(client.private_key)
10✔
190
     }}
191
  end
192
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc