From e71da9281cfe4fdbba4a6bc08268b6673077d89b Mon Sep 17 00:00:00 2001
From: pgvandelden
Date: Mon, 22 Mar 2021 11:36:57 +0100
Subject: [PATCH] use signature_method dynamically in api call
---
lib/lti_result.ex | 33 ++--
test/lti_result_test.exs | 380 ++++++++++++++++++++++-----------------
2 files changed, 231 insertions(+), 182 deletions(-)
diff --git a/lib/lti_result.ex b/lib/lti_result.ex
index 5274c36..f1478ff 100644
--- a/lib/lti_result.ex
+++ b/lib/lti_result.ex
@@ -27,24 +27,26 @@ defmodule LTIResult do
{:ok, "iyyQNRQyXTlpLJPJns3ireWjQxo%3D"}
"""
def signature(url, oauth_header, secret) do
- {parameters, [{"oauth_signature", received_signature}]} =
- extract_header_elements(oauth_header)
-
- with {:ok, _} <- validate_parameters(parameters) do
- basestring = base_string(url, parameters)
-
- signature = generate_signature(secret, basestring)
-
- if signature == received_signature do
- {:ok, signature}
- else
- {:error, [:unmatching_signatures]}
+ with {parameters, [{"oauth_signature", received_signature}]} <-
+ extract_header_elements(oauth_header),
+ {:ok, _} <- validate_parameters(parameters),
+ {_, signature_method} <-
+ List.keyfind(parameters, "oauth_signature_method", 0),
+ basestring <- base_string(url, parameters),
+ signature <- generate_signature(secret, signature_method, basestring) do
+ case signature == received_signature do
+ true ->
+ {:ok, signature}
+
+ false ->
+ {:error, [:unmatching_signatures]}
end
end
end
- defp generate_signature(secret, basestring) do
- :sha
+ defp generate_signature(secret, signature_method, basestring) do
+ signature_method
+ |> get_signature_method()
|> :crypto.hmac(
percent_encode(secret) <> "&",
basestring
@@ -52,6 +54,9 @@ defmodule LTIResult do
|> Base.encode64()
end
+ defp get_signature_method("HMAC-SHA256"), do: :sha256
+ defp get_signature_method(_), do: :sha
+
defp extract_header_elements(header) do
header
|> String.trim_leading("OAuth ")
diff --git a/test/lti_result_test.exs b/test/lti_result_test.exs
index 77f1cbf..5d54a04 100644
--- a/test/lti_result_test.exs
+++ b/test/lti_result_test.exs
@@ -2,175 +2,219 @@ defmodule LTIResultTest do
use ExUnit.Case
doctest LTIResult, only: [signature: 4]
- test "returns {:ok, determined_signature} if the signature is correct" do
- return =
- LTIResult.signature(
- "https://example.com",
- "OAuth oauth_consumer_key=\"key1234\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1525076552\",oauth_nonce=\"123\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
- "random_secret"
- )
-
- assert return == {:ok, "iyyQNRQyXTlpLJPJns3ireWjQxo="}
+ describe "signature_method SHMAC-SHA1" do
+ test "returns {:ok, determined_signature} if the signature is correct" do
+ return =
+ LTIResult.signature(
+ "https://example.com",
+ "OAuth oauth_consumer_key=\"key1234\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1525076552\",oauth_nonce=\"123\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
+ "random_secret"
+ )
+
+ assert return == {:ok, "iyyQNRQyXTlpLJPJns3ireWjQxo="}
+ end
+
+ test "returns identical signatures for downcase url and url with capitals" do
+ return1 =
+ LTIResult.signature(
+ "https://example.com",
+ "OAuth oauth_consumer_key=\"key1234\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1525076552\",oauth_nonce=\"123\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
+ "random_secret"
+ )
+
+ return2 =
+ LTIResult.signature(
+ "https://ExamPle.com",
+ "OAuth oauth_consumer_key=\"key1234\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1525076552\",oauth_nonce=\"123\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
+ "random_secret"
+ )
+
+ assert return1 == return2
+ end
+
+ test "returns {:ok, determined_signature} if a bodyhash is included" do
+ return =
+ LTIResult.signature(
+ "http://474c3d0e.ngrok.io/capp11/api/v1/lti_results",
+ "OAuth oauth_version=\"1.0\",oauth_nonce=\"tjtwip19l78355dl\",oauth_timestamp=\"1528808890\",oauth_consumer_key=\"Defacto\",oauth_body_hash=\"qvrl3dbLTUqxHeCDqof%2Ffz%2Bygc0%3D\",oauth_signature_method=\"HMAC-SHA1\",oauth_signature=\"WF9NUX6QCgKXNb2nNYEZ4evBmSk%3D\"",
+ "random_secret"
+ )
+
+ assert return == {:ok, "WF9NUX6QCgKXNb2nNYEZ4evBmSk="}
+ end
+
+ test "returns an error if the signature is incorrect due to difference in key" do
+ return =
+ LTIResult.signature(
+ "https://example.com",
+ "OAuth oauth_consumer_key=\"key12345\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1525076552\",oauth_nonce=\"123\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
+ "random_secret"
+ )
+
+ assert return == {:error, [:unmatching_signatures]}
+ end
+
+ test "returns an error if the signature is incorrect due to difference in method" do
+ return =
+ LTIResult.signature(
+ "https://example.com",
+ "OAuth oauth_consumer_key=\"key1234\",oauth_signature_method=\"HMAC-SHA2\",oauth_timestamp=\"1525076552\",oauth_nonce=\"123\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
+ "random_secret"
+ )
+
+ assert return == {:error, [:unmatching_signatures]}
+ end
+
+ test "returns an error if the signature is incorrect due to difference in timestamp" do
+ return =
+ LTIResult.signature(
+ "https://example.com",
+ "OAuth oauth_consumer_key=\"key1234\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"152500000\",oauth_nonce=\"123\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
+ "random_secret"
+ )
+
+ assert return == {:error, [:unmatching_signatures]}
+ end
+
+ test "returns an error if the signature is incorrect due to difference in nonce" do
+ return =
+ LTIResult.signature(
+ "https://example.com",
+ "OAuth oauth_consumer_key=\"key1234\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1525076552\",oauth_nonce=\"32123\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
+ "random_secret"
+ )
+
+ assert return == {:error, [:unmatching_signatures]}
+ end
+
+ test "returns an error if version is incorrect" do
+ return =
+ LTIResult.signature(
+ "https://example.com",
+ "OAuth oauth_consumer_key=\"key1234\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1525076552\",oauth_nonce=\"123\",oauth_version=\"2.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
+ "random_secret"
+ )
+
+ assert return == {:error, [:incorrect_version]}
+ end
+
+ test "returns an error if duplicated parameters are present" do
+ return =
+ LTIResult.signature(
+ "https://example.com",
+ "OAuth oauth_consumer_key=\"key1234\",oauth_consumer_key=\"key1234\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1525076552\",oauth_nonce=\"123\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
+ "random_secret"
+ )
+
+ assert return == {:error, [:duplicated_parameters]}
+ end
+
+ test "returns an error if the consumer key is missing" do
+ return =
+ LTIResult.signature(
+ "https://example.com",
+ "OAuth oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1525076552\",oauth_nonce=\"123\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
+ "random_secret"
+ )
+
+ assert return == {:error, [:missing_required_parameters]}
+ end
+
+ test "returns an error if the signature method is missing" do
+ return =
+ LTIResult.signature(
+ "https://example.com",
+ "OAuth oauth_consumer_key=\"key1234\",oauth_timestamp=\"1525076552\",oauth_nonce=\"123\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
+ "random_secret"
+ )
+
+ assert return == {:error, [:missing_required_parameters]}
+ end
+
+ test "returns an error if the timestamp is missing" do
+ return =
+ LTIResult.signature(
+ "https://example.com",
+ "OAuth oauth_consumer_key=\"key1234\",oauth_signature_method=\"HMAC-SHA1\",oauth_nonce=\"123\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
+ "random_secret"
+ )
+
+ assert return == {:error, [:missing_required_parameters]}
+ end
+
+ test "returns an error if oauth version is missing" do
+ return =
+ LTIResult.signature(
+ "https://example.com",
+ "OAuth oauth_consumer_key=\"key1234\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1525076552\",oauth_nonce=\"123\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
+ "random_secret"
+ )
+
+ assert return == {:error, [:incorrect_version, :missing_required_parameters]}
+ end
+
+ test "returns an error if nonce is missing" do
+ return =
+ LTIResult.signature(
+ "https://example.com",
+ "OAuth oauth_consumer_key=\"key1234\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1525076552\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
+ "random_secret"
+ )
+
+ assert return == {:error, [:missing_required_parameters]}
+ end
+
+ test "returns an error if an unsupported parameter is provided" do
+ return =
+ LTIResult.signature(
+ "https://example.com",
+ "OAuth unsupported_derpvalue=\"123\",oauth_consumer_key=\"key1234\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1525076552\",oauth_nonce=\"123\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
+ "random_secret"
+ )
+
+ assert return == {:error, [:unsupported_parameters]}
+ end
end
- test "returns identical signatures for downcase url and url with capitals" do
- return1 =
- LTIResult.signature(
- "https://example.com",
- "OAuth oauth_consumer_key=\"key1234\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1525076552\",oauth_nonce=\"123\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
- "random_secret"
- )
-
- return2 =
- LTIResult.signature(
- "https://ExamPle.com",
- "OAuth oauth_consumer_key=\"key1234\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1525076552\",oauth_nonce=\"123\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
- "random_secret"
- )
-
- assert return1 == return2
- end
-
- test "returns {:ok, determined_signature} if a bodyhash is included" do
- return =
- LTIResult.signature(
- "http://474c3d0e.ngrok.io/capp11/api/v1/lti_results",
- "OAuth oauth_version=\"1.0\",oauth_nonce=\"tjtwip19l78355dl\",oauth_timestamp=\"1528808890\",oauth_consumer_key=\"Defacto\",oauth_body_hash=\"qvrl3dbLTUqxHeCDqof%2Ffz%2Bygc0%3D\",oauth_signature_method=\"HMAC-SHA1\",oauth_signature=\"WF9NUX6QCgKXNb2nNYEZ4evBmSk%3D\"",
- "random_secret"
- )
-
- assert return == {:ok, "WF9NUX6QCgKXNb2nNYEZ4evBmSk="}
- end
-
- test "returns an error if the signature is incorrect due to difference in key" do
- return =
- LTIResult.signature(
- "https://example.com",
- "OAuth oauth_consumer_key=\"key12345\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1525076552\",oauth_nonce=\"123\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
- "random_secret"
- )
-
- assert return == {:error, [:unmatching_signatures]}
- end
-
- test "returns an error if the signature is incorrect due to difference in method" do
- return =
- LTIResult.signature(
- "https://example.com",
- "OAuth oauth_consumer_key=\"key1234\",oauth_signature_method=\"HMAC-SHA2\",oauth_timestamp=\"1525076552\",oauth_nonce=\"123\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
- "random_secret"
- )
-
- assert return == {:error, [:unmatching_signatures]}
- end
-
- test "returns an error if the signature is incorrect due to difference in timestamp" do
- return =
- LTIResult.signature(
- "https://example.com",
- "OAuth oauth_consumer_key=\"key1234\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"152500000\",oauth_nonce=\"123\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
- "random_secret"
- )
-
- assert return == {:error, [:unmatching_signatures]}
- end
-
- test "returns an error if the signature is incorrect due to difference in nonce" do
- return =
- LTIResult.signature(
- "https://example.com",
- "OAuth oauth_consumer_key=\"key1234\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1525076552\",oauth_nonce=\"32123\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
- "random_secret"
- )
-
- assert return == {:error, [:unmatching_signatures]}
- end
-
- test "returns an error if version is incorrect" do
- return =
- LTIResult.signature(
- "https://example.com",
- "OAuth oauth_consumer_key=\"key1234\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1525076552\",oauth_nonce=\"123\",oauth_version=\"2.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
- "random_secret"
- )
-
- assert return == {:error, [:incorrect_version]}
- end
-
- test "returns an error if duplicated parameters are present" do
- return =
- LTIResult.signature(
- "https://example.com",
- "OAuth oauth_consumer_key=\"key1234\",oauth_consumer_key=\"key1234\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1525076552\",oauth_nonce=\"123\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
- "random_secret"
- )
-
- assert return == {:error, [:duplicated_parameters]}
- end
-
- test "returns an error if the consumer key is missing" do
- return =
- LTIResult.signature(
- "https://example.com",
- "OAuth oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1525076552\",oauth_nonce=\"123\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
- "random_secret"
- )
-
- assert return == {:error, [:missing_required_parameters]}
- end
-
- test "returns an error if the signature method is missing" do
- return =
- LTIResult.signature(
- "https://example.com",
- "OAuth oauth_consumer_key=\"key1234\",oauth_timestamp=\"1525076552\",oauth_nonce=\"123\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
- "random_secret"
- )
-
- assert return == {:error, [:missing_required_parameters]}
- end
-
- test "returns an error if the timestamp is missing" do
- return =
- LTIResult.signature(
- "https://example.com",
- "OAuth oauth_consumer_key=\"key1234\",oauth_signature_method=\"HMAC-SHA1\",oauth_nonce=\"123\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
- "random_secret"
- )
-
- assert return == {:error, [:missing_required_parameters]}
- end
-
- test "returns an error if oauth version is missing" do
- return =
- LTIResult.signature(
- "https://example.com",
- "OAuth oauth_consumer_key=\"key1234\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1525076552\",oauth_nonce=\"123\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
- "random_secret"
- )
-
- assert return == {:error, [:incorrect_version, :missing_required_parameters]}
- end
-
- test "returns an error if nonce is missing" do
- return =
- LTIResult.signature(
- "https://example.com",
- "OAuth oauth_consumer_key=\"key1234\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1525076552\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
- "random_secret"
- )
-
- assert return == {:error, [:missing_required_parameters]}
- end
-
- test "returns an error if an unsupported parameter is provided" do
- return =
- LTIResult.signature(
- "https://example.com",
- "OAuth unsupported_derpvalue=\"123\",oauth_consumer_key=\"key1234\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1525076552\",oauth_nonce=\"123\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
- "random_secret"
- )
-
- assert return == {:error, [:unsupported_parameters]}
+ describe "signature_method SHMAC-SHA256" do
+ test "returns {:ok, determined_signature} if the signature is correct" do
+ return =
+ LTIResult.signature(
+ "https://example.com",
+ "OAuth oauth_consumer_key=\"key1234\",oauth_signature_method=\"HMAC-SHA256\",oauth_timestamp=\"1525076552\",oauth_nonce=\"123\",oauth_version=\"1.0\",oauth_signature=\"wLwhR7dk5e4dVsvlhjK+fyWKSGzKw+v+tO96twgaHI8%3D\"",
+ "random_secret"
+ )
+
+ assert return == {:ok, "wLwhR7dk5e4dVsvlhjK+fyWKSGzKw+v+tO96twgaHI8="}
+ end
+
+ test "returns identical signatures for downcase url and url with capitals" do
+ return1 =
+ LTIResult.signature(
+ "https://example.com",
+ "OAuth oauth_consumer_key=\"key1234\",oauth_signature_method=\"HMAC-SHA256\",oauth_timestamp=\"1525076552\",oauth_nonce=\"123\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
+ "random_secret"
+ )
+
+ return2 =
+ LTIResult.signature(
+ "https://ExamPle.com",
+ "OAuth oauth_consumer_key=\"key1234\",oauth_signature_method=\"HMAC-SHA256\",oauth_timestamp=\"1525076552\",oauth_nonce=\"123\",oauth_version=\"1.0\",oauth_signature=\"iyyQNRQyXTlpLJPJns3ireWjQxo%3D\"",
+ "random_secret"
+ )
+
+ assert return1 == return2
+ end
+
+ test "returns {:ok, determined_signature} if a bodyhash is included" do
+ return =
+ LTIResult.signature(
+ "http://474c3d0e.ngrok.io/capp11/api/v1/lti_results",
+ "OAuth oauth_version=\"1.0\",oauth_nonce=\"tjtwip19l78355dl\",oauth_timestamp=\"1528808890\",oauth_consumer_key=\"Defacto\",oauth_body_hash=\"qvrl3dbLTUqxHeCDqof%2Ffz%2Bygc0%3D\",oauth_signature_method=\"HMAC-SHA256\",oauth_signature=\"aols3rXaIgpdQ9Ux4jQtbSl9E/AX+kvl7xp6BPzzzmk%3D\"",
+ "random_secret"
+ )
+
+ assert return == {:ok, "aols3rXaIgpdQ9Ux4jQtbSl9E/AX+kvl7xp6BPzzzmk="}
+ end
end
end