Skip to content

Commit

Permalink
#3 access control entry data to hold the data for access control entr…
Browse files Browse the repository at this point in the history
…ies support is added
  • Loading branch information
Krishnakant C authored and Krishnakant C committed Sep 10, 2024
1 parent 54528d2 commit 92d7493
Show file tree
Hide file tree
Showing 2 changed files with 331 additions and 0 deletions.
207 changes: 207 additions & 0 deletions pkg/acl/access_control_entry_data.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
// Copyright 2024 Atomstate Technologies Private Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package acl

import "fmt"

// AccessControlEntryData holds the data for access control entries.
type AccessControlEntryData struct {
principal string
host string
operation AclOperation
permissionType AclPermissionType
}

// NewAccessControlEntryData creates a new AccessControlEntryData instance.
//
// Parameters:
// - principal: The principal (user or entity) associated with the entry.
// - host: The host associated with the entry.
// - operation: The ACL operation that this entry allows or denies.
// - permissionType: The type of permission (ALLOW, DENY, etc.) associated with the entry.
//
// Returns:
// A pointer to a new AccessControlEntryData instance.
//
// Example usage:
//
// entry := NewAccessControlEntryData("user1", "localhost", OpRead, ALLOW)
func NewAccessControlEntryData(
principal, host string,
operation AclOperation,
permissionType AclPermissionType) *AccessControlEntryData {
return &AccessControlEntryData{
principal: principal,
host: host,
operation: operation,
permissionType: permissionType,
}
}

// Principal returns the principal associated with the entry.
//
// Returns:
// The principal as a string.
//
// Example usage:
//
// principal := entry.Principal()
func (a *AccessControlEntryData) Principal() string {
return a.principal
}

// Host returns the host associated with the entry.
//
// Returns:
// The host as a string.
//
// Example usage:
//
// host := entry.Host()
func (a *AccessControlEntryData) Host() string {
return a.host
}

// Operation returns the ACL operation associated with the entry.
//
// Returns:
// The ACL operation as an AclOperation type.
//
// Example usage:
//
// operation := entry.Operation()
func (a *AccessControlEntryData) Operation() AclOperation {
return a.operation
}

// PermissionType returns the permission type associated with the entry.
//
// Returns:
// The permission type as an AclPermissionType type.
//
// Example usage:
//
// permissionType := entry.PermissionType()
func (a *AccessControlEntryData) PermissionType() AclPermissionType {
return a.permissionType
}

// FindIndefiniteField checks for indefinite fields and returns a corresponding message.
//
// Returns:
// A string message indicating which field is indefinite, or an empty string if all fields are defined.
//
// Example usage:
//
// message := entry.FindIndefiniteField()
func (a *AccessControlEntryData) FindIndefiniteField() string {
switch {
case a.principal == "":
return "Principal is NULL"
case a.host == "":
return "Host is NULL"
case a.operation == OpAny:
return "Operation is ANY"
case a.operation == OpUnknown:
return "Operation is UNKNOWN"
case a.permissionType == ANY:
return "Permission type is ANY"
case a.permissionType == UNKNOWN:
return "Permission type is UNKNOWN"
default:
return ""
}
}

// IsUnknown checks if there are any UNKNOWN components in the entry.
//
// Returns:
// A boolean indicating whether the entry contains any UNKNOWN components.
//
// Example usage:
//
// if entry.IsUnknown() {
// fmt.Println("Entry contains unknown components.")
// }
func (a *AccessControlEntryData) IsUnknown() bool {
return a.operation == OpUnknown || a.permissionType == UNKNOWN
}

// String returns a string representation of the AccessControlEntryData.
//
// Returns:
// A formatted string that represents the AccessControlEntryData instance.
//
// Example usage:
//
// fmt.Println(entry.String())
func (a *AccessControlEntryData) String() string {
principalStr := "<any>"
if a.principal != "" {
principalStr = a.principal
}
hostStr := "<any>"
if a.host != "" {
hostStr = a.host
}
return fmt.Sprintf("(principal=%s, host=%s, operation=%d, permissionType=%d)",
principalStr,
hostStr,
a.operation,
a.permissionType)
}

// Equals checks if two AccessControlEntryData instances are equal.
//
// Parameters:
// - other: A pointer to another AccessControlEntryData instance to compare against.
//
// Returns:
// A boolean indicating whether the two instances are equal.
//
// Example usage:
//
// if entry.Equals(otherEntry) {
// fmt.Println("Entries are equal.")
// }
func (a *AccessControlEntryData) Equals(other *AccessControlEntryData) bool {
if other == nil {
return false
}
return a.principal == other.principal &&
a.host == other.host &&
a.operation == other.operation &&
a.permissionType == other.permissionType
}

// HashCode returns a hash code for the AccessControlEntryData.
//
// Returns:
// An integer representing the hash code of the instance.
//
// Example usage:
//
// hash := entry.HashCode()
func (a *AccessControlEntryData) HashCode() int {
hash := 0
for _, char := range a.principal {
hash += int(char)
}
for _, char := range a.host {
hash += int(char)
}
hash += int(a.operation) + int(a.permissionType)
return hash
}
124 changes: 124 additions & 0 deletions pkg/acl/access_control_entry_data_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// Copyright 2024 Atomstate Technologies Private Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package acl

import "testing"

func TestNewAccessControlEntryData(t *testing.T) {
entry := NewAccessControlEntryData("user1", "localhost", OpRead, ALLOW)

if entry.Principal() != "user1" {
t.Errorf("Expected principal user1, got %s", entry.Principal())
}
if entry.Host() != "localhost" {
t.Errorf("Expected host localhost, got %s", entry.Host())
}
if entry.Operation() != OpRead {
t.Errorf("Expected operation OpRead, got %d", entry.Operation())
}
if entry.PermissionType() != ALLOW {
t.Errorf("Expected permission type ALLOW, got %d", entry.PermissionType())
}
}

func TestFindIndefiniteField(t *testing.T) {
tests := []struct {
name string
entry *AccessControlEntryData
expected string
}{
{"Nil Principal", NewAccessControlEntryData("", "localhost", OpRead, ALLOW), "Principal is NULL"},
{"Nil Host", NewAccessControlEntryData("user1", "", OpRead, ALLOW), "Host is NULL"},
{"Any Operation", NewAccessControlEntryData("user1", "localhost", OpAny, ALLOW), "Operation is ANY"},
{"Unknown Operation", NewAccessControlEntryData("user1", "localhost", OpUnknown, ALLOW), "Operation is UNKNOWN"},
{"Any Permission Type", NewAccessControlEntryData("user1", "localhost", OpRead, ANY), "Permission type is ANY"},
{"Unknown Permission Type", NewAccessControlEntryData("user1", "localhost", OpRead, UNKNOWN), "Permission type is UNKNOWN"},
{"All Fields Valid", NewAccessControlEntryData("user1", "localhost", OpRead, ALLOW), ""},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := tt.entry.FindIndefiniteField()
if result != tt.expected {
t.Errorf("Expected %s, got %s", tt.expected, result)
}
})
}
}

func TestIsUnknown(t *testing.T) {
tests := []struct {
entry *AccessControlEntryData
expected bool
}{
{NewAccessControlEntryData("user1", "localhost", OpUnknown, ALLOW), true},
{NewAccessControlEntryData("user1", "localhost", OpRead, UNKNOWN), true},
{NewAccessControlEntryData("user1", "localhost", OpRead, ALLOW), false},
}

for _, tt := range tests {
result := tt.entry.IsUnknown()
if result != tt.expected {
t.Errorf("Expected %v, got %v", tt.expected, result)
}
}
}

func TestString(t *testing.T) {
entry := NewAccessControlEntryData("user1", "localhost", OpRead, ALLOW)
expected := "(principal=user1, host=localhost, operation=3, permissionType=3)"
if entry.String() != expected {
t.Errorf("Expected %s, got %s", expected, entry.String())
}
}

func TestEquals(t *testing.T) {
entry1 := NewAccessControlEntryData("user1", "localhost", OpRead, ALLOW)
entry2 := NewAccessControlEntryData("user1", "localhost", OpRead, ALLOW)
entry3 := NewAccessControlEntryData("user2", "localhost", OpRead, ALLOW)

if !entry1.Equals(entry2) {
t.Errorf("Expected entries to be equal")
}
if entry1.Equals(entry3) {
t.Errorf("Expected entries to be different")
}
if entry1.Equals(nil) {
t.Errorf("Expected entry1 to not equal nil")
}
}

func TestHashCode(t *testing.T) {
entry := NewAccessControlEntryData("user1", "localhost", OpRead, ALLOW)
expectedHash := entry.HashCode() // Store the expected hash
if entry.HashCode() != expectedHash {
t.Errorf("Hash code should remain consistent; got %d", entry.HashCode())
}

// Test with different entries
entry2 := NewAccessControlEntryData("user2", "localhost", OpRead, ALLOW)
if entry.HashCode() == entry2.HashCode() {
t.Errorf("Expected different hash codes for different entries")
}
}

func TestHashCodeConsistency(t *testing.T) {
entry := NewAccessControlEntryData("user1", "localhost", OpRead, ALLOW)
hash1 := entry.HashCode()
hash2 := entry.HashCode()
if hash1 != hash2 {
t.Errorf("Hash code should be consistent; got %d and %d", hash1, hash2)
}
}

0 comments on commit 92d7493

Please sign in to comment.