Skip to content

Commit

Permalink
continue
Browse files Browse the repository at this point in the history
  • Loading branch information
eliasjpr committed Oct 9, 2024
1 parent 5073197 commit 2ee8f43
Show file tree
Hide file tree
Showing 18 changed files with 207 additions and 318 deletions.
20 changes: 7 additions & 13 deletions spec/authly_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ describe Authly do
code: code)

if id_token = token.id_token
id_token_decoded = Authly.decode_token(id_token).first
id_token_decoded = Authly.decode_token(id_token)

token.should be_a Authly::AccessToken
id_token_decoded["user_id"].should eq "username"
Expand Down Expand Up @@ -119,30 +119,24 @@ describe Authly do
end
end

describe ".introspect" do
describe ".inspect" do
it "returns active token" do
a_token = Authly::AccessToken.new(client_id, scope)
expected_token = Authly.decode_token(a_token.access_token).first
token = Authly.introspect(a_token.access_token)
expected_token = Authly.decode_token(a_token.access_token)
token = Authly.inspect(a_token.access_token)

token.should eq({
active: true,
scope: scope,
cid: client_id,
exp: a_token.expires_in,
sub: expected_token["sub"],
})
token.should eq({active: true, token: expected_token})
end

it "returns inactive token" do
token = Authly.introspect("invalid_token")
token = Authly.inspect("invalid_token")

token.should eq({active: false})
end

it "returns inactive token" do
a_token = Authly::AccessToken.new(client_id, scope)
token = Authly.introspect(a_token.to_s + "invalid")
token = Authly.inspect(a_token.to_s + "invalid")

token.should eq({active: false})
end
Expand Down
44 changes: 11 additions & 33 deletions spec/configuration_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -14,38 +14,16 @@ describe Authly::Configuration do
config.issuer.should eq("New Issuer")
end

describe Authly::SecurityConfiguration do
it "generates default secret and public keys" do
security_config = Authly::Configuration.instance.security
security_config.secret_key.should_not be_nil
security_config.public_key.should_not be_nil
end

it "uses HS256 as default algorithm" do
security_config = Authly::Configuration.instance.security
security_config.algorithm.should eq(JWT::Algorithm::HS256)
end
end

describe Authly::TTLConfiguration do
it "sets default TTL values" do
ttl_config = Authly::Configuration.instance.ttl
ttl_config.refresh_ttl.should eq(1.day)
ttl_config.code_ttl.should eq(5.minutes)
ttl_config.access_ttl.should eq(1.hour)
end
end

describe Authly::ProvidersConfiguration do
it "creates default owners and clients" do
provider_config = Authly::Configuration.instance.providers
provider_config.owners.should_not be_nil
provider_config.clients.should_not be_nil
end

it "sets a default JTI provider" do
provider_config = Authly::Configuration.instance.providers
provider_config.jti_provider.should be_a(Authly::InMemoryJTIProvider)
end
it "generates default secret and public keys" do
config = Authly::Configuration.instance
config.secret_key.should_not be_nil
config.public_key.should_not be_nil
config.algorithm.should eq(JWT::Algorithm::HS256)
config.refresh_ttl.should eq(1.day)
config.code_ttl.should eq(5.minutes)
config.access_ttl.should eq(1.hour)
config.owners.should_not be_nil
config.clients.should_not be_nil
config.token_store.should be_a(Authly::InMemoryTokenStore)
end
end
2 changes: 1 addition & 1 deletion spec/grant_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ module Authly
method: "S256",
verifier: "valid_verifier")

expect_raises(Authly::Error(400)) { grant.authorized? }
expect_raises(Authly::Error(400)) { grant.authorized? }
end
end

Expand Down
8 changes: 0 additions & 8 deletions spec/spec_helper.cr
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,5 @@ require "base64"
require "faker"
require "../src/authly"

# Configure
secret_key = Random::Secure.hex(16)

Authly.configure do |config|
config.security.secret_key = secret_key
config.security.public_key = secret_key
end

Authly.clients << Authly::Client.new("example", "secret", "https://www.example.com/callback", "1")
Authly.owners << Authly::Owner.new("username", "password")
32 changes: 14 additions & 18 deletions src/authly.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,29 @@ require "jwt"
require "json"
require "./authly/authorizable_owner"
require "./authly/authorizable_client"
require "./authly/jti_provider"
require "./authly/token_store_provider"
require "./authly/**"
require "log"

module Authly
CONFIG = Configuration.instance

alias HashToken = Hash(String, Int64 | String)

def self.configure(&)
yield CONFIG
with CONFIG yield CONFIG
end

def self.config
CONFIG
end

def self.clients
CONFIG.providers.clients
CONFIG.clients
end

def self.owners
CONFIG.providers.owners
CONFIG.owners
end

def self.code(response_type, *args)
Expand All @@ -34,32 +36,26 @@ module Authly
end

def self.encode_token(payload)
token_manager = TokenManager.new
token_manager.encode(payload)
config.token_strategy.encode(payload)
end

def self.decode_token(token)
token_manager = TokenManager.new
token_manager.decode(token)
config.token_strategy.decode(token)
end

def self.revoke(token)
token_manager = TokenManager.new
token_manager.revoke(token)
config.token_strategy.revoke!(token)
end

def self.revoke?(token)
token_manager = TokenManager.new
token_manager.revoke?(token)
def self.revoked?(token)
config.token_strategy.revoked?(token)
end

def self.valid?(token)
token_manager = TokenManager.new
token_manager.valid?(token)
config.token_strategy.valid?(token)
end

def self.introspect(token : String)
token_manager = TokenManager.new
token_manager.introspect(token)
def self.inspect(token : String)
config.token_strategy.inspect(token)
end
end
9 changes: 5 additions & 4 deletions src/authly/access_token.cr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
module Authly
struct AccessToken
include JSON::Serializable
ACCESS_TTL = Authly.config.ttl.access_ttl
REFRESH_TTL = Authly.config.ttl.refresh_ttl
ACCESS_TTL = Authly.config.access_ttl
REFRESH_TTL = Authly.config.refresh_ttl

# The JWT ID (jti), used to track and revoke individual tokens
getter jti : String
Expand All @@ -22,14 +22,14 @@ module Authly
end

def initialize(@client_id : String, @scope : String, @id_token : String? = nil)
@jti = Random::Secure.hex(32) # Generate a unique jti for each token
@jti = Random::Secure.base64 # Generate a unique jti for each token
@access_token = generate_token
@refresh_token = refresh_token
end

private def generate_token
Authly.encode_token({
"sub" => Random::Secure.hex(32),
"sub" => Random::Secure.base64,
"iss" => Authly.config.issuer,
"cid" => @client_id,
"iat" => Time.utc.to_unix,
Expand All @@ -42,6 +42,7 @@ module Authly
def refresh_token
Authly.encode_token({
"sub" => @client_id,
"iss" => Authly.config.issuer,
"name" => "refresh token",
"iat" => Time.utc.to_unix,
"exp" => REFRESH_TTL.from_now.to_unix,
Expand Down
10 changes: 7 additions & 3 deletions src/authly/code.cr
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
module Authly
struct Code
include JSON::Serializable
CODE_TTL = Authly.config.ttl.code_ttl
CODE_TTL = Authly.config.code_ttl

@secret_key : String = Authly.config.secret_key
@algorithm : JWT::Algorithm = Authly.config.algorithm

getter code : String = Random::Secure.hex(16),
client_id : String,
Expand All @@ -22,16 +25,17 @@ module Authly
end

def jwt
Authly.encode_token({
JWT.encode({
"code" => code,
"challenge" => challenge,
"method" => method,
"scope" => scope,
"user_id" => user_id,
"redirect_uri" => redirect_uri,
"iss" => Authly.config.issuer,
"iat" => Time.utc.to_unix,
"exp" => CODE_TTL.from_now.to_unix,
})
}, @secret_key, @algorithm)
end

def to_s
Expand Down
71 changes: 10 additions & 61 deletions src/authly/configuration.cr
Original file line number Diff line number Diff line change
@@ -1,72 +1,21 @@
module Authly
# Security Configuration
class SecurityConfiguration
# Configuration class using Singleton and Builder Pattern
class Configuration
class_getter instance : Configuration = Configuration.new

property owners : AuthorizableOwner = Owners.new
property clients : AuthorizableClient = Clients.new
property token_store : TokenStoreProvider = InMemoryTokenStore.new
property secret_key : String = Random::Secure.hex(16)
property public_key : String = Random::Secure.hex(16)
property algorithm : JWT::Algorithm = JWT::Algorithm::HS256
end

# Time-To-Live Configuration
class TTLConfiguration
property issuer : String = "The Authority Server Provider"
property refresh_ttl : Time::Span = 1.day
property code_ttl : Time::Span = 5.minutes
property access_ttl : Time::Span = 1.hour
end

# Providers Configuration
class ProvidersConfiguration
property owners : AuthorizableOwner = Owners.new
property clients : AuthorizableClient = Clients.new
property jti_provider : JTIProvider = InMemoryJTIProvider.new
end

# Configuration class using Singleton and Builder Pattern
class Configuration
property issuer : String = "The Authority Server Provider"
property security : SecurityConfiguration = SecurityConfiguration.new
property ttl : TTLConfiguration = TTLConfiguration.new
property providers : ProvidersConfiguration = ProvidersConfiguration.new
property token_type : String = "jwt"

# Singleton instance
@@instance : Configuration?

def self.instance : Configuration
@@instance ||= Configuration.new
end

def initialize
end

# Builder for Configuration
class Builder
def initialize
@configuration = Configuration.new
end

def issuer(issuer : String) : self
@configuration.issuer = issuer
self
end

def security(security : SecurityConfiguration) : self
@configuration.security = security
self
end

def ttl(ttl : TTLConfiguration) : self
@configuration.ttl = ttl
self
end

def owner_client(owner_client : ProvidersConfiguration) : self
@configuration.owner_client = owner_client
self
end

def build : Configuration
Configuration.instance
end
getter token_strategy : TokenStrategy do
TokenFactory.create
end
end
end
5 changes: 5 additions & 0 deletions src/authly/error.cr
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,14 @@ module Authly
unsupported_grant_type: "Invalid or unknown grant type",
access_denied: "The user or authorization server denied the request",
unsupported_token_type: "The authorization server does not support the revocation of the presented token type",
invalid_token: "The token is invalid or expired",
}

class Error(Code) < Exception
def self.invalid_token
raise Error(400).new(:invalid_token)
end

def self.unsupported_token_type
raise Error(400).new(:unsupported_token_type)
end
Expand Down
9 changes: 6 additions & 3 deletions src/authly/grant.cr
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,20 @@ module Authly

private def generate_id_token
if scope.includes? "openid"
Authly.encode_token Authly.owners.id_token auth_code["user_id"].as_s
user_id = auth_code["user_id"].to_s
Authly.encode_token Authly.owners.id_token(user_id)
end
end

private def auth_code
Authly.decode_token(@code).first
puts Authly.decode_token(@code)
Authly.decode_token(@code)
end

private def scope : String
return "" if @code.empty?
auth_code["scope"].as_s
puts
auth_code["scope"].to_s
end
end
end
3 changes: 2 additions & 1 deletion src/authly/grants/authorization_code.cr
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ module Authly
@redirect_uri : String,
@challenge : String = "",
@method : String = "",
@verifier : String= "")
@verifier : String = ""
)
end

def authorized? : Bool
Expand Down
Loading

0 comments on commit 2ee8f43

Please sign in to comment.