Skip to content

Commit

Permalink
feat(elixir): update influxdb token lease manager response api
Browse files Browse the repository at this point in the history
use typed Identifier() instead of strings, and unix epoch to represent
dates.

Also updates ockam client, to issue requests to the root path "/".
  • Loading branch information
polvorin committed Sep 25, 2024
1 parent a743805 commit 12fb589
Show file tree
Hide file tree
Showing 9 changed files with 79 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ defmodule Ockam.Services.TokenLeaseManager do
def authorize(:identity, %Request{} = req, _bindings) do
case Request.caller_identity_id(req) do
{:ok, identity_id} ->
{true, %{identity_id: Identifier.to_str(identity_id)}}
{true, %{identity_id: identity_id}}

:error ->
false
Expand All @@ -45,7 +45,11 @@ defmodule Ockam.Services.TokenLeaseManager do
state: %{storage_service: storage, storage_service_config: storage_config}
}) do
{:ok, leases} = storage.get_all(storage_config, identity_id)
Logger.info("found #{Enum.count(leases)} leases for identity #{identity_id}")

Logger.info(
"found #{Enum.count(leases)} leases for identity #{Identifier.to_str(identity_id)}"
)

Lease.encode_list(leases)
end

Expand Down Expand Up @@ -129,7 +133,7 @@ defmodule Ockam.Services.TokenLeaseManager do
def schedule_expire(lease) do
# TODO: internally it should be datetimes always, serialize when
# we need to send it over the wire.
{:ok, expires, _offset} = DateTime.from_iso8601(lease.expires)
{:ok, expires} = DateTime.from_unix(lease.expires)
now = DateTime.utc_now()
expires_in = max(DateTime.diff(expires, now, :millisecond), 0)
:timer.send_after(expires_in, {:expire, lease.id, lease.issued_for})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ defmodule Ockam.Services.TokenLeaseManager.CloudService do
@type creation_options :: map()

@callback init(options) :: {:ok, cloud_configuration} | {:error, reason}
@callback create(cloud_configuration, identity_id :: String.t(), ttl: integer()) ::
@callback create(cloud_configuration, identifier :: Ockam.Identity.Identifier.t(),
ttl: integer()
) ::
{:ok, lease} | {:error, reason}
@callback revoke(cloud_configuration, token_id) :: :ok | {:error, reason}
@callback get_all(cloud_configuration) :: {:ok, [lease]} | {:error, reason}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ defmodule Ockam.Services.TokenLeaseManager.CloudService.Influxdb do
- permissions (json string) - default set of permissions new tokens are granted
"""
@behaviour Ockam.Services.TokenLeaseManager.CloudService
alias Ockam.Identity.Identifier
alias Ockam.Services.TokenLeaseManager.Lease
require Logger

Expand Down Expand Up @@ -45,7 +46,7 @@ defmodule Ockam.Services.TokenLeaseManager.CloudService.Influxdb do
options = %{
"permissions" => cloud_configuration[:permissions],
"orgID" => cloud_configuration[:org_id],
"description" => "ockam/#{identity_id}/#{DateTime.to_iso8601(expires)}"
"description" => "ockam/#{Identifier.to_str(identity_id)}/#{DateTime.to_iso8601(expires)}"
}

{:ok, body} = Poison.encode(options)
Expand Down Expand Up @@ -124,15 +125,21 @@ defmodule Ockam.Services.TokenLeaseManager.CloudService.Influxdb do
ockam_metadata = auth["description"]

with ["ockam", issued_for, expires] <- String.split(ockam_metadata, "/"),
{:ok, _expire_date, _offset} <- DateTime.from_iso8601(expires) do
{:ok, expire_date, _offset} <- DateTime.from_iso8601(expires),
{:ok, issued_date, _offset} <- DateTime.from_iso8601(auth["createdAt"]) do
{:ok,
%Lease{
id: auth["id"],
issued_for: issued_for,
expires: expires,
issued: auth["createdAt"],
issued_for: Identifier.from_str(issued_for),
expires: DateTime.to_unix(expire_date),
issued: DateTime.to_unix(issued_date),
value: auth["token"],
status: auth["status"]
status:
if auth["status"] == "active" do
:active
else
:revoked
end
}}
else
other ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,17 @@ defmodule Ockam.Services.TokenLeaseManager.Lease do
typedstruct do
plugin(Ockam.TypedCBOR.Plugin)
field(:id, String.t(), minicbor: [key: 1])
field(:issued_for, String.t(), minicbor: [key: 2])
field(:issued, String.t(), minicbor: [key: 3])
field(:expires, String.t(), minicbor: [key: 4])

field(:issued_for, Ockam.Identity.Identifier.t(),
minicbor: [schema: Ockam.Identity.Identifier, key: 2]
)

field(:issued, integer(), minicbor: [key: 3])
field(:expires, integer(), minicbor: [key: 4])
field(:value, String.t(), minicbor: [key: 5])
field(:status, String.t(), minicbor: [key: 6])

field(:status, :active | :revoked,
minicbor: [schema: {:enum, [active: 0, revoked: 1]}, key: 6]
)
end
end
Original file line number Diff line number Diff line change
@@ -1,44 +1,53 @@
defmodule Ockam.Services.TokenLeaseManager.Storage.Memory.Test do
use ExUnit.Case

alias Ockam.Identity
alias Ockam.Services.TokenLeaseManager.Lease
alias Ockam.Services.TokenLeaseManager.StorageService.Memory, as: Storage

@leases [
%Lease{id: "1", value: "vvvv", issued_for: "id1"},
%Lease{id: "2", value: "vvvv", issued_for: "id2"},
%Lease{id: "3", value: "vvvv", issued_for: "id1"}
]

setup do
{:ok, state} = Ockam.Services.TokenLeaseManager.StorageService.Memory.init(leases: @leases)
[state: state]
{:ok, identity1} = Identity.create()
id1 = Identity.get_identifier(identity1)
{:ok, identity2} = Identity.create()
id2 = Identity.get_identifier(identity2)
{:ok, identity3} = Identity.create()
id3 = Identity.get_identifier(identity3)

leases = [
%Lease{id: "1", value: "vvvv", issued_for: id1},
%Lease{id: "2", value: "vvvv", issued_for: id2},
%Lease{id: "3", value: "vvvv", issued_for: id1}
]

{:ok, state} = Ockam.Services.TokenLeaseManager.StorageService.Memory.init(leases: leases)

[state: state, id1: id1, id2: id2, id3: id3]
end

test "get lease", %{state: state} do
assert {:ok, %Lease{id: "3"}} = Storage.get(state, "id1", "3")
assert {:ok, nil} = Storage.get(state, "id1", "4")
test "get lease", %{state: state, id1: id1} do
assert {:ok, %Lease{id: "3"}} = Storage.get(state, id1, "3")
assert {:ok, nil} = Storage.get(state, id1, "4")
end

test "list leases", %{state: state} do
assert {:ok, []} = Storage.get_all(state, "id3")
assert {:ok, [%Lease{id: "2"}]} = Storage.get_all(state, "id2")
{:ok, r} = Storage.get_all(state, "id1")
test "list leases", %{state: state, id1: id1, id2: id2, id3: id3} do
assert {:ok, []} = Storage.get_all(state, id3)
assert {:ok, [%Lease{id: "2"}]} = Storage.get_all(state, id2)
{:ok, r} = Storage.get_all(state, id1)
assert [%Lease{id: "1"}, %Lease{id: "3"}] = Enum.sort(r)
end

test "store leases", %{state: state} do
:ok = Storage.save(state, %Lease{id: "4", issued_for: "id2"})
:ok = Storage.save(state, %Lease{id: "5", issued_for: "id3"})
assert {:ok, [%Lease{id: "5"}]} = Storage.get_all(state, "id3")
{:ok, r} = Storage.get_all(state, "id2")
test "store leases", %{state: state, id2: id2, id3: id3} do
:ok = Storage.save(state, %Lease{id: "4", issued_for: id2})
:ok = Storage.save(state, %Lease{id: "5", issued_for: id3})
assert {:ok, [%Lease{id: "5"}]} = Storage.get_all(state, id3)
{:ok, r} = Storage.get_all(state, id2)
assert [%Lease{id: "2"}, %Lease{id: "4"}] = Enum.sort(r)
end

test "remove leases", %{state: state} do
:ok = Storage.remove(state, "id1", "1")
:ok = Storage.remove(state, "id2", "2")
assert {:ok, []} = Storage.get_all(state, "id2")
assert {:ok, [%Lease{id: "3"}]} = Storage.get_all(state, "id1")
test "remove leases", %{state: state, id1: id1, id2: id2} do
:ok = Storage.remove(state, id1, "1")
:ok = Storage.remove(state, id2, "2")
assert {:ok, []} = Storage.get_all(state, id2)
assert {:ok, [%Lease{id: "3"}]} = Storage.get_all(state, id1)
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,18 @@ defmodule Ockam.Services.API.Tests.FakeCloudService do
def init(_config), do: {:ok, []}

@impl true
def create(_config, identity_id, ttl) do
def create(_config, identifier, ttl) do
now = DateTime.utc_now()
expires = DateTime.add(now, ttl, :second)

{:ok,
%Lease{
id: "ID_#{:rand.uniform(65536)}",
issued: DateTime.to_iso8601(now),
issued_for: identity_id,
expires: DateTime.to_iso8601(expires),
issued: DateTime.to_unix(now),
issued_for: identifier,
expires: DateTime.to_unix(expires),
value: "TOKEN_#{:rand.uniform(65536)}",
status: "active"
status: :active
}}
end

Expand All @@ -34,7 +34,6 @@ defmodule Ockam.Services.TokenLeaseManager.Test do

alias Ockam.API.Client
alias Ockam.Identity
alias Ockam.Identity.Identifier
alias Ockam.SecureChannel
alias Ockam.Services.TokenLeaseManager
alias Ockam.Services.TokenLeaseManager.Lease
Expand Down Expand Up @@ -108,8 +107,8 @@ defmodule Ockam.Services.TokenLeaseManager.Test do
short_live_lm: short_live_lm,
bob_channel: bob_channel,
alice_channel: alice_channel,
bob_id: Identifier.to_str(bob_id),
alice_id: Identifier.to_str(alice_id),
bob_id: bob_id,
alice_id: alice_id,
listener: listener
]
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ pub trait InfluxDBTokenLessorNodeServiceTrait {
#[async_trait]
impl InfluxDBTokenLessorNodeServiceTrait for InMemoryNode {
async fn create_token(&self, ctx: &Context, at: &MultiAddr) -> miette::Result<LeaseToken> {
let req = Request::post("").to_vec().into_diagnostic()?;
let req = Request::post("/").to_vec().into_diagnostic()?;
let bytes = self.send_message(ctx, at, req, None).await?;
Response::parse_response_body::<LeaseToken>(bytes.as_slice()).into_diagnostic()
}
Expand Down Expand Up @@ -208,7 +208,7 @@ impl InfluxDBTokenLessorNodeServiceTrait for InMemoryNode {
}

async fn list_tokens(&self, ctx: &Context, at: &MultiAddr) -> miette::Result<Vec<LeaseToken>> {
let req = Request::get("").to_vec().into_diagnostic()?;
let req = Request::get("/").to_vec().into_diagnostic()?;
let bytes = self.send_message(ctx, at, req, None).await?;
Response::parse_response_body::<Vec<LeaseToken>>(bytes.as_slice()).into_diagnostic()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ impl InfluxDBTokenLessorWorker {
};
debug!(path_segments = ?path_segments.as_slice().iter().map(|s| s.to_string()).collect::<Vec<_>>(), "Handling request");

// [""] correspond to the root "/" path
let r = match (method, path_segments.as_slice()) {
(Post, [""]) => encode_response(req, self.create_token(requester).await)?,
(Get, [""]) => encode_response(req, self.list_tokens(requester).await)?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ impl Eq for LeaseToken {}
#[derive(
Encode, Decode, CborLen, Serialize, Deserialize, PartialEq, Debug, Clone, EnumString, Display,
)]
#[cbor(index_only)]
pub enum TokenStatus {
#[n(0)]
#[strum(serialize = "active")]
Expand Down

0 comments on commit 12fb589

Please sign in to comment.