Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add authentications #73

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
53 changes: 50 additions & 3 deletions Sources/RSocketCore/Extensions/Security/Authentication.swift
Expand Up @@ -19,20 +19,46 @@ import NIOCore
public struct Authentication {
public var type: AuthenticationType
public var payload: ByteBuffer
public init(type: AuthenticationType, payload: ByteBuffer) {
self.type = type
self.payload = payload
}
}

public struct AuthenticationDecoder: MetadataDecoder {
@inlinable
public var mimeType: MIMEType { .messageXRSocketAuthenticationV0 }

@inlinable
public func decode(from buffer: inout ByteBuffer) throws -> Authentication {
fatalError("not implemented")
let idOrLength = buffer.readBytes(length: 1)?.withUnsafeBytes{ value -> UInt8 in
return value.load(as: UInt8.self)
}
debugPrint(idOrLength! & 0x7F)
debugPrint(idOrLength!)
switch idOrLength! & 0x7F {
case WellKnownAuthenticationType.SIMPLE.identifier :
return Authentication(type: AuthenticationType.simple,payload: buffer)
case WellKnownAuthenticationType.BEARER.identifier:
return Authentication(type: AuthenticationType.bearer ,payload: buffer)
default :
return Authentication(type: AuthenticationType(rawValue: buffer.readString(length: Int(idOrLength!)) ?? "") ,payload: buffer)
}

}
}

extension MetadataDecoder where Self == AuthenticationDecoder {
public static var authentication: Self { .init() }

//Return ID or Auth Length
public static func isWellKnownAuthType(_ buffer : ByteBuffer) -> Bool{
var tmp = buffer
guard let authType = (tmp.readBytes(length: 1)?.withUnsafeBytes{ value -> UInt8 in return value.load(as: UInt8.self).bigEndian}) else{
return false
}
let idOrLength = UInt8(authType & 0x7F)
return idOrLength != authType
}
}

public struct AuthenticationEncoder: MetadataEncoder {
Expand All @@ -41,7 +67,28 @@ public struct AuthenticationEncoder: MetadataEncoder {

@inlinable
public func encode(_ metadata: Authentication, into buffer: inout ByteBuffer) throws {
fatalError("not implemented")
switch metadata.type{
case .bearer:
buffer.mergeByteBuffers(buffers: [ByteBuffer(integer: UInt8(WellKnownAuthenticationType.BEARER.identifier )), metadata.payload])
case .simple:
buffer.mergeByteBuffers(buffers: [ByteBuffer(integer: UInt8(WellKnownAuthenticationType.SIMPLE.identifier)),
metadata.payload])
default:
try encodeCustomMetadata(customAuthType: metadata.type.rawValue, metadata: metadata.payload , into: &buffer)
}
}

@inlinable
public func encodeCustomMetadata(customAuthType: String, metadata: ByteBuffer , into buffer: inout ByteBuffer) throws {
do {
try buffer.writeLengthPrefixed(as: UInt8.self) { buffer in
buffer.writeString(customAuthType)
}
} catch {
throw Error.invalid(message: "MIME Type \(mimeType) too long to encode")
}
var aux = metadata
buffer.writeBuffer(&aux)
}
}

Expand Down
Expand Up @@ -25,3 +25,53 @@ public extension AuthenticationType {
static let simple = Self(rawValue: "simple")
static let bearer = Self(rawValue: "bearer")
}


public enum WellKnownAuthenticationType : Equatable {
case UNPARSEABLE_AUTH_TYPE
case UNKNOWN_RESERVED_AUTH_TYPE
case SIMPLE
case BEARER

private static var typesByAuthId = [WellKnownAuthenticationType](repeating: .UNKNOWN_RESERVED_AUTH_TYPE, count: 128)

public static func fromIdentifier(id: Int8) -> WellKnownAuthenticationType {
if id < 0x00 || id > 0x7F {
return .UNPARSEABLE_AUTH_TYPE
}
return typesByAuthId[Int(id)]
}

public var identifier: UInt8 {
switch self {
case .UNPARSEABLE_AUTH_TYPE :
return UInt8(0xFE)
case .UNKNOWN_RESERVED_AUTH_TYPE:
return UInt8(0xFF)
case .SIMPLE:
return 0x00
case .BEARER:
return 0x01
}
}
}

//public enum WellKnownAuthenticationType {
// case BEARER
// case SIMPLE
// case UNPARSEABLE_AUTH_TYPE
// case UNKNOWN_RESERVED_AUTH_TYPE
//
// public var identifier: UInt8 {
// switch self {
// case .SIMPLE:
// return UInt8(0x00)
// case .BEARER:
// return UInt8(0x01)
// case .UNKNOWN_RESERVED_AUTH_TYPE:
// return UInt8(0xFF)
// case .UNPARSEABLE_AUTH_TYPE:
// return UInt8(0xFE)
// }
// }
//}
14 changes: 12 additions & 2 deletions Sources/RSocketCore/Extensions/Security/Bearer.swift
Expand Up @@ -25,7 +25,14 @@ public struct BearerAuthenticationDecoder: MetadataDecoder {

@inlinable
public func decode(from buffer: inout ByteBuffer) throws -> String {
fatalError("not implemented")
guard AuthenticationDecoder.isWellKnownAuthType(buffer) else {
throw Error.invalid(message: "invalid bearar metadata")
}
_ = buffer.readBytes(length: 1)
guard let token = buffer.readString(length: buffer.readableBytes) else{
throw Error.invalid(message: "no token")
}
return token
}
}

Expand All @@ -43,7 +50,10 @@ public struct BearerAuthenticationEncoder: MetadataEncoder {

@inlinable
public func encode(_ metadata: String, into buffer: inout ByteBuffer) throws {
fatalError("not implemented")
buffer = buffer.mergeByteBuffers(buffers:[
ByteBuffer(integer: UInt8(WellKnownAuthenticationType.BEARER.identifier) | UInt8(0x80)),
ByteBuffer(string: metadata) // Token
])
}
}

Expand Down
65 changes: 65 additions & 0 deletions Sources/RSocketCore/Extensions/Security/Custom.swift
@@ -0,0 +1,65 @@
//
// File.swift
//
//
// Created by Elyes Ben Salah on 6/2/2023.
//


import NIOCore


public struct CustomAuthenticationDecoder: MetadataDecoder {
@usableFromInline
internal var authenticationDecoder: AuthenticationDecoder = .init()

@inlinable
public var mimeType: MIMEType { authenticationDecoder.mimeType }


public func decode(from buffer: inout ByteBuffer) throws -> Authentication {
guard var slice = buffer.readLengthPrefixedSlice(as: UInt8.self),
let customAuthType = slice.readString(length: slice.readableBytes)
else {
throw Error.invalid(message: "authType could not be read")
}

return .init(type: AuthenticationType(rawValue: customAuthType), payload: ByteBuffer(bytes: buffer.readBytes(length: buffer.readableBytes) ?? []))
}
}

extension MetadataDecoder where Self == CustomAuthenticationDecoder {
public static var customAuthentication: Self { .init() }
}


public struct CustomAuthenticationEncoder: MetadataEncoder {
@usableFromInline
internal var authenticationEncoder: AuthenticationEncoder = .init()

@inlinable
public var mimeType: MIMEType { authenticationEncoder.mimeType }

@inlinable
public func encode(_ metadata: Authentication , into buffer: inout ByteBuffer) throws {
try encodeCustomMetadata(metadata, into: &buffer)
}

@inlinable
public func encodeCustomMetadata(_ customAuth : Authentication , into buffer: inout ByteBuffer) throws {
do {
try buffer.writeLengthPrefixed(as: UInt8.self) { buffer in
buffer.writeString(customAuth.type.rawValue)
}
} catch {
throw Error.invalid(message: "MIME Type \(mimeType) too long to encode")
}
var aux = customAuth.payload
buffer.writeBuffer(&aux)
}

}

extension MetadataEncoder where Self == CustomAuthenticationEncoder {
public static var customAuthentication: Self { .init() }
}
28 changes: 26 additions & 2 deletions Sources/RSocketCore/Extensions/Security/Simple.swift
Expand Up @@ -34,7 +34,27 @@ public struct SimpleAuthenticationDecoder: MetadataDecoder {

@inlinable
public func decode(from buffer: inout ByteBuffer) throws -> SimpleAuthentication {
fatalError("not implemented")
let _ = buffer.readBytes(length: 1)?.withUnsafeBytes{ value -> UInt8 in
return value.load(as: UInt8.self).bigEndian
}
guard var slice = buffer.readLengthPrefixedSlice(as: UInt16.self),
let username = slice.readString(length: slice.readableBytes)
else {
throw Error.invalid(message: "username could not be read")
}
let password = buffer.readString(length: buffer.readableBytes)
return SimpleAuthentication(username: username ,password : password ?? "")
}

@inlinable
func extractSimpleAuth(username : String, password : String , into buffer : inout ByteBuffer ) {
let usernameLength = UInt16(username.utf8.count) // 2 bits
var bufferLength = ByteBufferAllocator().buffer(capacity: 2)
bufferLength.writeInteger(usernameLength)
buffer = buffer.mergeByteBuffers(buffers: [ByteBuffer(integer: UInt8(WellKnownAuthenticationType.SIMPLE.identifier)),
bufferLength,
ByteBuffer(string: username),
ByteBuffer(string: password)])
}
}

Expand All @@ -52,7 +72,11 @@ public struct SimpleAuthenticationEncoder: MetadataEncoder {

@inlinable
public func encode(_ metadata: SimpleAuthentication, into buffer: inout ByteBuffer) throws {
fatalError("not implemented")
buffer.writeInteger(UInt8(WellKnownAuthenticationType.SIMPLE.identifier) | UInt8(0x80))
try buffer.writeLengthPrefixed(as: UInt16.self) { buffer in
try buffer.writeString(metadata.username, encoding: .utf8)
}
try buffer.writeString(metadata.password, encoding: .utf8)
}
}

Expand Down
11 changes: 11 additions & 0 deletions Sources/RSocketCore/Utility/ByteBuffer+UInt24.swift
Expand Up @@ -110,4 +110,15 @@ extension ByteBuffer {
moveReaderIndex(forwardBy: 3)
return integer
}

@discardableResult
@inlinable
internal mutating func mergeByteBuffers(buffers: [ByteBuffer]) -> ByteBuffer {
let totalLength = buffers.reduce(0){ $0 + $1.readableBytes}
var mergedBuffer = ByteBufferAllocator().buffer(capacity: totalLength)
for buff in buffers {
mergedBuffer.writeBytes(buff.getBytes(at: 0, length: buff.readableBytes) ?? [] )
}
return mergedBuffer
}
}
102 changes: 102 additions & 0 deletions Tests/RSocketCoreTests/Extensions/Security/SecurityTests.swift
@@ -0,0 +1,102 @@
//
// SecurityTests.swift
//
//
// Created by Elyes Ben Salah on 3/2/2023.
//


import XCTest
import NIOCore
@testable import RSocketCore


final class SecurityTests: XCTestCase {


func testTest() throws {
let encoder = AuthenticationEncoder()
let decoder = AuthenticationDecoder()

var resultEncoder = ByteBuffer()
let authentication = Authentication(type : .init(rawValue: "kindi"), payload: ByteBuffer(string: "someDataForKindiAuth"))
try encoder.encode(authentication , into: &resultEncoder)
let resultDecoder = try decoder.decode(from: &resultEncoder)

debugPrint(resultDecoder.type)
}


func testBearerAuth() throws {
let encoder = BearerAuthenticationEncoder()
let decoder = BearerAuthenticationDecoder()

var resultEncoder = ByteBuffer()
try encoder.encode("Token",into: &resultEncoder)
let data = resultEncoder.getBytes(at: 0, length: resultEncoder.readableBytes)!
debugPrint(data)
var buffToDecode = ByteBuffer(bytes: data)
let authRz = try decoder.decode(from: &buffToDecode)

debugPrint("Bearer Auth Decoded \nToken : \(authRz)")

}

func testSimpleAuth() throws {
let encoder = SimpleAuthenticationEncoder()
let decoder = SimpleAuthenticationDecoder()
let auth = SimpleAuthentication(username: "LoginasjdjqfjeqfjnqefkqenkqegknqegknqefknqefasjdjqfjeqfjnqefkqenkqegknqegknqegknqefknqefknLoginasjdjqfjeqfjnqefkqenkq", password: "Passwordqqn")
var resultEncoder = ByteBuffer()
try encoder.encode(auth,into: &resultEncoder)
debugPrint(resultEncoder.getBytes(at: 0, length: resultEncoder.readableBytes)!)
debugPrint(resultEncoder.getString(at: 0, length: resultEncoder.readableBytes)!)

let authRz = try decoder.decode(from: &resultEncoder)
debugPrint(authRz)

}
func testCustomAuth() throws {
let encoder = CustomAuthenticationEncoder()
let decoder = CustomAuthenticationDecoder()

var resultEncoder = ByteBuffer()
let authentication = Authentication(type : .init(rawValue: "kindi"), payload: ByteBuffer(string: "someDataForKindiAuth"))

try encoder.encode(authentication,into: &resultEncoder)
let data = resultEncoder.getBytes(at: 0, length: resultEncoder.readableBytes)!
debugPrint(data)
var buffToDecode = ByteBuffer(bytes: data)
var authRz = try decoder.decode(from: &buffToDecode)

debugPrint("Custom Auth Decoded :\nType : \(authRz.type.rawValue)\nData : \(authRz.payload.readString(length: authRz.payload.readableBytes))")

}


func testWellKnowAuthTypes() throws {
//Simple Auth
let simpleEncoder = SimpleAuthenticationEncoder()
let simpleAuth = SimpleAuthentication(username: "LoginasjdjqfjeqfjnqefkqenkqegknqegknqefknqefknLoginasjdjqfjeqfjnqefkqenkqegknqegknqefknqefknLoginasjdjqfjeqfjnqefkqenkqegknqegknqefknqefknLoginasjdjqfjeqfjnqefkqenkqegknqegknqefknqefknLoginasjdjqfjeqfjnqefkqenkqegknqegknqefknqefknLoginasjdjqfjeqfjnqefkqenkq", password: "Passwordqqn")
var simpleAuthBuffer = ByteBuffer()
try simpleEncoder.encode(simpleAuth,into: &simpleAuthBuffer)
let resultSimple = AuthenticationDecoder.isWellKnownAuthType(simpleAuthBuffer)

//Bearer Auth
let bearerEncoder = BearerAuthenticationEncoder()
var bearerAuthBuffer = ByteBuffer()
try bearerEncoder.encode("MyToken",into: &bearerAuthBuffer)
let bearerResult = AuthenticationDecoder.isWellKnownAuthType(bearerAuthBuffer)


//Custom Auth
let customEncoder = CustomAuthenticationEncoder()
var customAuthBuffer = ByteBuffer()
let auth = Authentication(type : .init(rawValue: "Kindi"), payload : ByteBuffer(string: "SomeDataForKindiAuth"))
try customEncoder.encodeCustomMetadata(auth, into: &customAuthBuffer)
let customResult = AuthenticationDecoder.isWellKnownAuthType(customAuthBuffer)

debugPrint("isWellKnown SimpleAuth : \(resultSimple)")
debugPrint("isWellKnown BearerAuth : \(bearerResult)")
debugPrint("isWellKnown CustomAuth : \(!customResult)")
}
}