Showing preview only (1,081K chars total). Download the full file or copy to clipboard to get everything.
Repository: apache/casbin
Branch: master
Commit: 098508551fe3
Files: 225
Total size: 1018.9 KB
Directory structure:
gitextract_1o8_iigh/
├── .asf.yaml
├── .github/
│ ├── scripts/
│ │ ├── benchmark_formatter.py
│ │ ├── download_artifact.js
│ │ └── post_comment.js
│ ├── semantic.yml
│ └── workflows/
│ ├── comment.yml
│ ├── default.yml
│ ├── golangci-lint.yml
│ └── performance-pr.yml
├── .gitignore
├── .golangci.yml
├── .releaserc.json
├── CONTRIBUTING.md
├── DISCLAIMER
├── LICENSE
├── Makefile
├── README.md
├── abac_test.go
├── ai_api.go
├── ai_api_test.go
├── biba_test.go
├── blp_test.go
├── config/
│ ├── config.go
│ ├── config_test.go
│ └── testdata/
│ └── testini.ini
├── constant/
│ └── constants.go
├── constraint_test.go
├── detector/
│ ├── default_detector.go
│ ├── default_detector_test.go
│ └── detector.go
├── effector/
│ ├── default_effector.go
│ └── effector.go
├── enforcer.go
├── enforcer_backslash_test.go
├── enforcer_cached.go
├── enforcer_cached_b_test.go
├── enforcer_cached_gfunction_test.go
├── enforcer_cached_synced.go
├── enforcer_cached_synced_test.go
├── enforcer_cached_test.go
├── enforcer_context.go
├── enforcer_context_interface.go
├── enforcer_context_test.go
├── enforcer_distributed.go
├── enforcer_interface.go
├── enforcer_json_test.go
├── enforcer_synced.go
├── enforcer_synced_test.go
├── enforcer_test.go
├── enforcer_transactional.go
├── error_test.go
├── errors/
│ ├── constraint_errors.go
│ └── rbac_errors.go
├── examples/
│ ├── abac_model.conf
│ ├── abac_not_using_policy_model.conf
│ ├── abac_rule_effect_policy.csv
│ ├── abac_rule_model.conf
│ ├── abac_rule_policy.csv
│ ├── basic_inverse_policy.csv
│ ├── basic_model.conf
│ ├── basic_model_without_spaces.conf
│ ├── basic_policy.csv
│ ├── basic_with_root_model.conf
│ ├── basic_without_resources_model.conf
│ ├── basic_without_resources_policy.csv
│ ├── basic_without_users_model.conf
│ ├── basic_without_users_policy.csv
│ ├── biba_model.conf
│ ├── blp_model.conf
│ ├── comment_model.conf
│ ├── error/
│ │ ├── error_model.conf
│ │ └── error_policy.csv
│ ├── eval_operator_model.conf
│ ├── eval_operator_policy.csv
│ ├── glob_model.conf
│ ├── glob_policy.csv
│ ├── ipmatch_model.conf
│ ├── ipmatch_policy.csv
│ ├── keyget2_model.conf
│ ├── keyget_model.conf
│ ├── keymatch2_model.conf
│ ├── keymatch2_policy.csv
│ ├── keymatch_custom_model.conf
│ ├── keymatch_model.conf
│ ├── keymatch_policy.csv
│ ├── keymatch_with_rbac_in_domain.conf
│ ├── keymatch_with_rbac_in_domain.csv
│ ├── lbac_model.conf
│ ├── multiple_policy_definitions_model.conf
│ ├── multiple_policy_definitions_policy.csv
│ ├── object_conditions_model.conf
│ ├── object_conditions_policy.csv
│ ├── orbac_model.conf
│ ├── orbac_policy.csv
│ ├── pbac_model.conf
│ ├── pbac_policy.csv
│ ├── performance/
│ │ ├── rbac_with_pattern_large_scale_model.conf
│ │ └── rbac_with_pattern_large_scale_policy.csv
│ ├── priority_indeterminate_policy.csv
│ ├── priority_model.conf
│ ├── priority_model_enforce_context.conf
│ ├── priority_model_explicit.conf
│ ├── priority_model_explicit_customized.conf
│ ├── priority_policy.csv
│ ├── priority_policy_enforce_context.csv
│ ├── priority_policy_explicit.csv
│ ├── priority_policy_explicit_customized.csv
│ ├── rbac_model.conf
│ ├── rbac_model_in_multi_line.conf
│ ├── rbac_model_matcher_using_in_op.conf
│ ├── rbac_model_matcher_using_in_op_bracket.conf
│ ├── rbac_policy.csv
│ ├── rbac_with_all_pattern_model.conf
│ ├── rbac_with_all_pattern_policy.csv
│ ├── rbac_with_constraints_model.conf
│ ├── rbac_with_cycle_policy.csv
│ ├── rbac_with_deny_model.conf
│ ├── rbac_with_deny_policy.csv
│ ├── rbac_with_different_types_of_roles_model.conf
│ ├── rbac_with_different_types_of_roles_policy.csv
│ ├── rbac_with_domain_pattern_model.conf
│ ├── rbac_with_domain_pattern_policy.csv
│ ├── rbac_with_domain_temporal_roles_model.conf
│ ├── rbac_with_domain_temporal_roles_policy.csv
│ ├── rbac_with_domains_conditional_model.conf
│ ├── rbac_with_domains_conditional_policy.csv
│ ├── rbac_with_domains_model.conf
│ ├── rbac_with_domains_policy.csv
│ ├── rbac_with_domains_policy2.csv
│ ├── rbac_with_hierarchy_policy.csv
│ ├── rbac_with_hierarchy_with_domains_policy.csv
│ ├── rbac_with_multiple_policy_model.conf
│ ├── rbac_with_multiple_policy_policy.csv
│ ├── rbac_with_not_deny_model.conf
│ ├── rbac_with_pattern_model.conf
│ ├── rbac_with_pattern_policy.csv
│ ├── rbac_with_resource_roles_model.conf
│ ├── rbac_with_resource_roles_policy.csv
│ ├── rbac_with_temporal_roles_model.conf
│ ├── rbac_with_temporal_roles_policy.csv
│ ├── rebac_model.conf
│ ├── rebac_policy.csv
│ ├── subject_priority_model.conf
│ ├── subject_priority_model_with_domain.conf
│ ├── subject_priority_policy.csv
│ ├── subject_priority_policy_with_domain.csv
│ └── syntax_matcher_model.conf
├── filter_test.go
├── frontend.go
├── frontend_old.go
├── frontend_old_test.go
├── frontend_test.go
├── go.mod
├── go.sum
├── internal_api.go
├── lbac_test.go
├── log/
│ ├── default_logger.go
│ ├── logger.go
│ └── types.go
├── logger_test.go
├── management_api.go
├── management_api_b_test.go
├── management_api_test.go
├── model/
│ ├── assertion.go
│ ├── constraint.go
│ ├── function.go
│ ├── model.go
│ ├── model_test.go
│ └── policy.go
├── model_b_test.go
├── model_test.go
├── orbac_test.go
├── pbac_test.go
├── persist/
│ ├── adapter.go
│ ├── adapter_context.go
│ ├── adapter_filtered.go
│ ├── adapter_filtered_context.go
│ ├── batch_adapter.go
│ ├── batch_adapter_context.go
│ ├── cache/
│ │ ├── cache.go
│ │ ├── cache_sync.go
│ │ └── default-cache.go
│ ├── dispatcher.go
│ ├── file-adapter/
│ │ ├── adapter.go
│ │ ├── adapter_context.go
│ │ ├── adapter_filtered.go
│ │ ├── adapter_filtered_context.go
│ │ └── adapter_mock.go
│ ├── persist_test.go
│ ├── string-adapter/
│ │ ├── adapter.go
│ │ ├── adapter_context.go
│ │ └── adapter_test.go
│ ├── transaction.go
│ ├── update_adapter.go
│ ├── update_adapter_context.go
│ ├── watcher.go
│ ├── watcher_ex.go
│ └── watcher_update.go
├── rbac/
│ ├── context_role_manager.go
│ ├── default-role-manager/
│ │ ├── role_manager.go
│ │ └── role_manager_test.go
│ └── role_manager.go
├── rbac_api.go
├── rbac_api_context.go
├── rbac_api_synced.go
├── rbac_api_test.go
├── rbac_api_with_domains.go
├── rbac_api_with_domains_context.go
├── rbac_api_with_domains_synced.go
├── rbac_api_with_domains_test.go
├── role_manager_b_test.go
├── syntax_test.go
├── transaction.go
├── transaction_buffer.go
├── transaction_commit.go
├── transaction_conflict.go
├── transaction_test.go
├── util/
│ ├── builtin_operators.go
│ ├── builtin_operators_test.go
│ ├── util.go
│ └── util_test.go
├── util_log.go
├── watcher_ex_test.go
├── watcher_test.go
└── watcher_update_test.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .asf.yaml
================================================
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
# For more information, see https://cwiki.apache.org/confluence/display/INFRA/Git+-+.asf.yaml+features.
github:
description: >-
Apache Casbin: an authorization library that supports access control models like ACL, RBAC, ABAC.
homepage: https://casbin.apache.org/
dependabot_alerts: true
dependabot_updates: false
notifications:
commits: commits@casbin.apache.org
================================================
FILE: .github/scripts/benchmark_formatter.py
================================================
import pathlib, re, sys
try:
p = pathlib.Path("comparison.md")
if not p.exists():
print("comparison.md not found, skipping post-processing.")
sys.exit(0)
lines = p.read_text(encoding="utf-8").splitlines()
processed_lines = []
in_code = False
def strip_worker_suffix(text: str) -> str:
return re.sub(r'(\S+?)-\d+(\s|$)', r'\1\2', text)
def get_icon(diff_val: float) -> str:
if diff_val > 10:
return "🐌"
if diff_val < -10:
return "🚀"
return "➡️"
def clean_superscripts(text: str) -> str:
return re.sub(r'[¹²³⁴⁵⁶⁷⁸⁹⁰]', '', text)
def parse_val(token: str):
if '%' in token or '=' in token:
return None
token = clean_superscripts(token)
token = token.split('±')[0].strip()
token = token.split('(')[0].strip()
if not token:
return None
m = re.match(r'^([-+]?\d*\.?\d+)([a-zA-Zµ]+)?$', token)
if not m:
return None
try:
val = float(m.group(1))
except ValueError:
return None
suffix = (m.group(2) or "").replace("µ", "u")
multipliers = {
"n": 1e-9,
"ns": 1e-9,
"u": 1e-6,
"us": 1e-6,
"m": 1e-3,
"ms": 1e-3,
"s": 1.0,
"k": 1e3,
"K": 1e3,
"M": 1e6,
"G": 1e9,
"Ki": 1024.0,
"Mi": 1024.0**2,
"Gi": 1024.0**3,
"Ti": 1024.0**4,
"B": 1.0,
"B/op": 1.0,
"C": 1.0, # tolerate degree/unit markers that don't affect ratio
}
return val * multipliers.get(suffix, 1.0)
def extract_two_numbers(tokens):
found = []
for t in tokens[1:]: # skip name
if t in {"±", "∞", "~", "│", "│"}:
continue
if '%' in t or '=' in t:
continue
val = parse_val(t)
if val is not None:
found.append(val)
if len(found) == 2:
break
return found
# Pass 0:
# 1. find a header line with pipes to derive alignment hint
# 2. calculate max content width to ensure right-most alignment
max_content_width = 0
for line in lines:
if line.strip() == "```":
in_code = not in_code
continue
if not in_code:
continue
# Skip footnotes/meta for width calculation
if re.match(r'^\s*[¹²³⁴⁵⁶⁷⁸⁹⁰]', line) or re.search(r'need\s*>?=\s*\d+\s+samples', line):
continue
if not line.strip() or line.strip().startswith(('goos:', 'goarch:', 'pkg:', 'cpu:')):
continue
# Header lines are handled separately in Pass 1
if '│' in line and ('vs base' in line or 'old' in line or 'new' in line):
continue
# It's likely a data line
# Check if it has an existing percentage we might move/align
curr_line = strip_worker_suffix(line).rstrip()
pct_match = re.search(r'([+-]?\d+\.\d+)%', curr_line)
if pct_match:
# If we are going to realign this, we count width up to the percentage
w = len(curr_line[:pct_match.start()].rstrip())
else:
w = len(curr_line)
if w > max_content_width:
max_content_width = w
# Calculate global alignment target for Diff column
# Ensure target column is beyond the longest line with some padding
diff_col_start = max_content_width + 4
# Calculate right boundary (pipe) position
# Diff column width ~12 chars (e.g. "+100.00% 🚀")
right_boundary = diff_col_start + 14
# Reset code fence tracking state for Pass 1
in_code = False
for line in lines:
if line.strip() == "```":
in_code = not in_code
processed_lines.append(line)
continue
if not in_code:
processed_lines.append(line)
continue
# footnotes keep untouched
if re.match(r'^\s*[¹²³⁴⁵⁶⁷⁸⁹⁰]', line) or re.search(r'need\s*>?=\s*\d+\s+samples', line):
processed_lines.append(line)
continue
# header lines: ensure last column labeled Diff and force alignment
if '│' in line and ('vs base' in line or 'old' in line or 'new' in line):
# Strip trailing pipe and whitespace
stripped_header = line.rstrip().rstrip('│').rstrip()
# If "vs base" is present, ensure we don't duplicate "Diff" if it's already there
# But we want to enforce OUR alignment, so we might strip existing Diff
stripped_header = re.sub(r'\s+Diff\s*$', '', stripped_header, flags=re.IGNORECASE)
stripped_header = re.sub(r'\s+Delta\b', '', stripped_header, flags=re.IGNORECASE)
# Pad to diff_col_start
if len(stripped_header) < diff_col_start:
new_header = stripped_header + " " * (diff_col_start - len(stripped_header))
else:
new_header = stripped_header + " "
# Add Diff column header if it's the second header row (vs base)
if 'vs base' in line:
new_header += "Diff"
# Add closing pipe at the right boundary
current_len = len(new_header)
if current_len < right_boundary:
new_header += " " * (right_boundary - current_len)
new_header += "│"
processed_lines.append(new_header)
continue
# non-data meta lines
if not line.strip() or line.strip().startswith(('goos:', 'goarch:', 'pkg:')):
processed_lines.append(line)
continue
line = strip_worker_suffix(line)
tokens = line.split()
if not tokens:
processed_lines.append(line)
continue
numbers = extract_two_numbers(tokens)
pct_match = re.search(r'([+-]?\d+\.\d+)%', line)
# Helper to align and append
def append_aligned(left_part, content):
if len(left_part) < diff_col_start:
aligned = left_part + " " * (diff_col_start - len(left_part))
else:
aligned = left_part + " "
# Ensure content doesn't exceed right boundary (visual check only, we don't truncate)
# But users asked not to exceed header pipe.
# Header pipe is at right_boundary.
# Content starts at diff_col_start.
# So content length should be <= right_boundary - diff_col_start
return f"{aligned}{content}"
# Special handling for geomean when values missing or zero
is_geomean = tokens[0] == "geomean"
if is_geomean and (len(numbers) < 2 or any(v == 0 for v in numbers)) and not pct_match:
leading = re.match(r'^\s*', line).group(0)
left = f"{leading}geomean"
processed_lines.append(append_aligned(left, "n/a (has zero)"))
continue
# when both values are zero, force diff = 0 and align
if len(numbers) == 2 and numbers[0] == 0 and numbers[1] == 0:
diff_val = 0.0
icon = get_icon(diff_val)
left = line.rstrip()
processed_lines.append(append_aligned(left, f"{diff_val:+.2f}% {icon}"))
continue
# recompute diff when we have two numeric values
if len(numbers) == 2 and numbers[0] != 0:
diff_val = (numbers[1] - numbers[0]) / numbers[0] * 100
icon = get_icon(diff_val)
left = line
if pct_match:
left = line[:pct_match.start()].rstrip()
else:
left = line.rstrip()
processed_lines.append(append_aligned(left, f"{diff_val:+.2f}% {icon}"))
continue
# fallback: align existing percentage to Diff column and (re)append icon
if pct_match:
try:
pct_val = float(pct_match.group(1))
icon = get_icon(pct_val)
left = line[:pct_match.start()].rstrip()
suffix = line[pct_match.end():]
# Remove any existing icon after the percentage to avoid duplicates
suffix = re.sub(r'\s*(🐌|🚀|➡️)', '', suffix)
processed_lines.append(append_aligned(left, f"{pct_val:+.2f}% {icon}{suffix}"))
except ValueError:
processed_lines.append(line)
continue
# If we cannot parse numbers or percentages, keep the original (only worker suffix stripped)
processed_lines.append(line)
p.write_text("\n".join(processed_lines) + "\n", encoding="utf-8")
except Exception as e:
print(f"Error post-processing comparison.md: {e}")
sys.exit(1)
================================================
FILE: .github/scripts/download_artifact.js
================================================
module.exports = async ({github, context, core}) => {
try {
const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
const matchArtifact = artifacts.data.artifacts.find((artifact) => {
return artifact.name == "benchmark-results";
});
if (!matchArtifact) {
core.setFailed("No artifact named 'benchmark-results' found.");
return;
}
const download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: 'zip',
});
const fs = require('fs');
const path = require('path');
const workspace = process.env.GITHUB_WORKSPACE;
fs.writeFileSync(path.join(workspace, 'benchmark-results.zip'), Buffer.from(download.data));
} catch (error) {
core.setFailed(`Failed to download artifact: ${error.message}`);
}
};
================================================
FILE: .github/scripts/post_comment.js
================================================
module.exports = async ({github, context, core}) => {
const fs = require('fs');
// Validate pr_number.txt
if (!fs.existsSync('pr_number.txt')) {
core.setFailed("Required artifact file 'pr_number.txt' was not found in the workspace.");
return;
}
const prNumberContent = fs.readFileSync('pr_number.txt', 'utf8').trim();
const issue_number = parseInt(prNumberContent, 10);
if (!Number.isFinite(issue_number) || issue_number <= 0) {
core.setFailed('Invalid PR number in pr_number.txt: "' + prNumberContent + '"');
return;
}
// Validate comparison.md
if (!fs.existsSync('comparison.md')) {
core.setFailed("Required artifact file 'comparison.md' was not found in the workspace.");
return;
}
let comparison;
try {
comparison = fs.readFileSync('comparison.md', 'utf8');
} catch (error) {
core.setFailed("Failed to read 'comparison.md': " + error.message);
return;
}
// Find existing comment
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue_number,
});
const botComment = comments.find(comment =>
comment.user.type === 'Bot' &&
comment.body.includes('Benchmark Comparison')
);
const footer = '<sub>🤖 This comment will be automatically updated with the latest benchmark results.</sub>';
const commentBody = `${comparison}\n\n${footer}`;
if (botComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: commentBody
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue_number,
body: commentBody
});
}
};
================================================
FILE: .github/semantic.yml
================================================
# Always validate the PR title AND all the commits
titleAndCommits: true
================================================
FILE: .github/workflows/comment.yml
================================================
name: Post Benchmark Comment
on:
workflow_run:
workflows: ["Performance Comparison for Pull Requests"]
types:
- completed
permissions:
pull-requests: write
jobs:
comment:
runs-on: ubuntu-latest
if: >
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success'
steps:
- name: Checkout repo
uses: actions/checkout@v4
- name: 'Download artifact'
uses: actions/github-script@v7
with:
script: |
const script = require('./.github/scripts/download_artifact.js')
await script({github, context, core})
- name: 'Unzip artifact'
run: unzip benchmark-results.zip
- name: 'Post comment'
uses: actions/github-script@v7
with:
script: |
const script = require('./.github/scripts/post_comment.js')
await script({github, context, core})
================================================
FILE: .github/workflows/default.yml
================================================
name: Build
on:
push:
branches:
- master
pull_request:
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
go: ['1.21']
steps:
- uses: actions/checkout@v2
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go }}
- name: Run go test
run: make test
benchmark:
runs-on: ubuntu-latest
strategy:
matrix:
go: ['1.21']
steps:
- uses: actions/checkout@v2
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go }}
- name: Run go test bench
run: make benchmark
semantic-release:
needs: test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 20
- name: Run semantic-release
if: github.repository == 'casbin/casbin' && github.event_name == 'push'
run: make release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
================================================
FILE: .github/workflows/golangci-lint.yml
================================================
name: golangci-lint
on:
push:
branches:
- master
- main
pull_request:
jobs:
golangci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.21'
- name: golangci-lint
uses: golangci/golangci-lint-action@v4
with:
version: v1.56.2
================================================
FILE: .github/workflows/performance-pr.yml
================================================
name: Performance Comparison for Pull Requests
on:
pull_request:
branches: [master]
jobs:
benchmark-pr:
name: Performance benchmark comparison
runs-on: ubuntu-latest
steps:
- name: Checkout PR branch
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: 'stable'
# Save commit SHAs for display
- name: Save commit info
id: commits
run: |
BASE_SHA="${{ github.event.pull_request.base.sha }}"
HEAD_SHA="${{ github.event.pull_request.head.sha }}"
echo "base_short=${BASE_SHA:0:7}" >> $GITHUB_OUTPUT
echo "head_short=${HEAD_SHA:0:7}" >> $GITHUB_OUTPUT
# Run benchmark on PR branch
- name: Run benchmark on PR branch
run: |
go test -bench '.' -benchtime=2s -benchmem ./... | tee pr-bench.txt
# Checkout base branch and run benchmark
- name: Checkout base branch
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.base.sha }}
clean: false
path: base
- name: Run benchmark on base branch
working-directory: base
run: |
go test -bench '.' -benchtime=2s -benchmem ./... | \
tee ../base-bench.txt
# Install benchstat for comparison
- name: Install benchstat
run: go install golang.org/x/perf/cmd/benchstat@latest
# Compare benchmarks using benchstat
- name: Compare benchmarks with benchstat
id: benchstat
run: |
cat > comparison.md << 'EOF'
## Benchmark Comparison
Comparing base branch (`${{ steps.commits.outputs.base_short }}`)
vs PR branch (`${{ steps.commits.outputs.head_short }}`)
```
EOF
benchstat base-bench.txt pr-bench.txt >> comparison.md || true
echo '```' >> comparison.md
# Post-process to append percentage + emoji column (🚀 faster < -10%, 🐌 slower > +10%, otherwise ➡️)
if [ ! -f comparison.md ]; then
echo "comparison.md not found after benchstat." >&2
exit 1
fi
python3 .github/scripts/benchmark_formatter.py
# Save PR number
- name: Save PR number
run: |
PR_NUMBER="${{ github.event.pull_request.number }}"
if [ -z "$PR_NUMBER" ]; then
echo "Error: Pull request number is not available in event payload." >&2
exit 1
fi
echo "$PR_NUMBER" > pr_number.txt
# Upload benchmark results
- name: Upload benchmark results
uses: actions/upload-artifact@v4
with:
name: benchmark-results
path: |
comparison.md
pr_number.txt
================================================
FILE: .gitignore
================================================
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
.idea/
*.iml
# vendor files
vendor
================================================
FILE: .golangci.yml
================================================
# Based on https://gist.github.com/maratori/47a4d00457a92aa426dbd48a18776322
# This code is licensed under the terms of the MIT license https://opensource.org/license/mit
# Copyright (c) 2021 Marat Reymers
## Golden config for golangci-lint v1.56.2
#
# This is the best config for golangci-lint based on my experience and opinion.
# It is very strict, but not extremely strict.
# Feel free to adapt and change it for your needs.
run:
# Timeout for analysis, e.g. 30s, 5m.
# Default: 1m
timeout: 3m
# This file contains only configs which differ from defaults.
# All possible options can be found here https://github.com/golangci/golangci-lint/blob/master/.golangci.reference.yml
linters-settings:
cyclop:
# The maximal code complexity to report.
# Default: 10
max-complexity: 30
# The maximal average package complexity.
# If it's higher than 0.0 (float) the check is enabled
# Default: 0.0
package-average: 10.0
errcheck:
# Report about not checking of errors in type assertions: `a := b.(MyStruct)`.
# Such cases aren't reported by default.
# Default: false
check-type-assertions: true
exhaustive:
# Program elements to check for exhaustiveness.
# Default: [ switch ]
check:
- switch
- map
exhaustruct:
# List of regular expressions to exclude struct packages and their names from checks.
# Regular expressions must match complete canonical struct package/name/structname.
# Default: []
exclude:
# std libs
- "^net/http.Client$"
- "^net/http.Cookie$"
- "^net/http.Request$"
- "^net/http.Response$"
- "^net/http.Server$"
- "^net/http.Transport$"
- "^net/url.URL$"
- "^os/exec.Cmd$"
- "^reflect.StructField$"
# public libs
- "^github.com/Shopify/sarama.Config$"
- "^github.com/Shopify/sarama.ProducerMessage$"
- "^github.com/mitchellh/mapstructure.DecoderConfig$"
- "^github.com/prometheus/client_golang/.+Opts$"
- "^github.com/spf13/cobra.Command$"
- "^github.com/spf13/cobra.CompletionOptions$"
- "^github.com/stretchr/testify/mock.Mock$"
- "^github.com/testcontainers/testcontainers-go.+Request$"
- "^github.com/testcontainers/testcontainers-go.FromDockerfile$"
- "^golang.org/x/tools/go/analysis.Analyzer$"
- "^google.golang.org/protobuf/.+Options$"
- "^gopkg.in/yaml.v3.Node$"
funlen:
# Checks the number of lines in a function.
# If lower than 0, disable the check.
# Default: 60
lines: 100
# Checks the number of statements in a function.
# If lower than 0, disable the check.
# Default: 40
statements: 50
# Ignore comments when counting lines.
# Default false
ignore-comments: true
gocognit:
# Minimal code complexity to report.
# Default: 30 (but we recommend 10-20)
min-complexity: 20
gocritic:
# Settings passed to gocritic.
# The settings key is the name of a supported gocritic checker.
# The list of supported checkers can be find in https://go-critic.github.io/overview.
settings:
captLocal:
# Whether to restrict checker to params only.
# Default: true
paramsOnly: false
underef:
# Whether to skip (*x).method() calls where x is a pointer receiver.
# Default: true
skipRecvDeref: false
gomnd:
# List of function patterns to exclude from analysis.
# Values always ignored: `time.Date`,
# `strconv.FormatInt`, `strconv.FormatUint`, `strconv.FormatFloat`,
# `strconv.ParseInt`, `strconv.ParseUint`, `strconv.ParseFloat`.
# Default: []
ignored-functions:
- flag.Arg
- flag.Duration.*
- flag.Float.*
- flag.Int.*
- flag.Uint.*
- os.Chmod
- os.Mkdir.*
- os.OpenFile
- os.WriteFile
- prometheus.ExponentialBuckets.*
- prometheus.LinearBuckets
gomodguard:
blocked:
# List of blocked modules.
# Default: []
modules:
- github.com/golang/protobuf:
recommendations:
- google.golang.org/protobuf
reason: "see https://developers.google.com/protocol-buffers/docs/reference/go/faq#modules"
- github.com/satori/go.uuid:
recommendations:
- github.com/google/uuid
reason: "satori's package is not maintained"
- github.com/gofrs/uuid:
recommendations:
- github.com/gofrs/uuid/v5
reason: "gofrs' package was not go module before v5"
govet:
# Enable all analyzers.
# Default: false
enable-all: true
# Disable analyzers by name.
# Run `go tool vet help` to see all analyzers.
# Default: []
disable:
- fieldalignment # too strict
# Settings per analyzer.
settings:
shadow:
# Whether to be strict about shadowing; can be noisy.
# Default: false
#strict: true
inamedparam:
# Skips check for interface methods with only a single parameter.
# Default: false
skip-single-param: true
nakedret:
# Make an issue if func has more lines of code than this setting, and it has naked returns.
# Default: 30
max-func-lines: 0
nolintlint:
# Exclude following linters from requiring an explanation.
# Default: []
allow-no-explanation: [ funlen, gocognit, lll ]
# Enable to require an explanation of nonzero length after each nolint directive.
# Default: false
require-explanation: true
# Enable to require nolint directives to mention the specific linter being suppressed.
# Default: false
require-specific: true
perfsprint:
# Optimizes into strings concatenation.
# Default: true
strconcat: false
rowserrcheck:
# database/sql is always checked
# Default: []
packages:
- github.com/jmoiron/sqlx
tenv:
# The option `all` will run against whole test files (`_test.go`) regardless of method/function signatures.
# Otherwise, only methods that take `*testing.T`, `*testing.B`, and `testing.TB` as arguments are checked.
# Default: false
all: true
stylecheck:
# STxxxx checks in https://staticcheck.io/docs/configuration/options/#checks
# Default: ["*"]
checks: ["all", "-ST1003"]
revive:
rules:
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unused-parameter
- name: unused-parameter
disabled: true
linters:
disable-all: true
enable:
## enabled by default
#- errcheck # checking for unchecked errors, these unchecked errors can be critical bugs in some cases
- gosimple # specializes in simplifying a code
- govet # reports suspicious constructs, such as Printf calls whose arguments do not align with the format string
- ineffassign # detects when assignments to existing variables are not used
- staticcheck # is a go vet on steroids, applying a ton of static analysis checks
- typecheck # like the front-end of a Go compiler, parses and type-checks Go code
- unused # checks for unused constants, variables, functions and types
## disabled by default
- asasalint # checks for pass []any as any in variadic func(...any)
- asciicheck # checks that your code does not contain non-ASCII identifiers
- bidichk # checks for dangerous unicode character sequences
- bodyclose # checks whether HTTP response body is closed successfully
- cyclop # checks function and package cyclomatic complexity
- dupl # tool for code clone detection
- durationcheck # checks for two durations multiplied together
- errname # checks that sentinel errors are prefixed with the Err and error types are suffixed with the Error
#- errorlint # finds code that will cause problems with the error wrapping scheme introduced in Go 1.13
- execinquery # checks query string in Query function which reads your Go src files and warning it finds
- exhaustive # checks exhaustiveness of enum switch statements
- exportloopref # checks for pointers to enclosing loop variables
#- forbidigo # forbids identifiers
- funlen # tool for detection of long functions
- gocheckcompilerdirectives # validates go compiler directive comments (//go:)
#- gochecknoglobals # checks that no global variables exist
- gochecknoinits # checks that no init functions are present in Go code
- gochecksumtype # checks exhaustiveness on Go "sum types"
#- gocognit # computes and checks the cognitive complexity of functions
#- goconst # finds repeated strings that could be replaced by a constant
#- gocritic # provides diagnostics that check for bugs, performance and style issues
- gocyclo # computes and checks the cyclomatic complexity of functions
- godot # checks if comments end in a period
- goimports # in addition to fixing imports, goimports also formats your code in the same style as gofmt
#- gomnd # detects magic numbers
- gomoddirectives # manages the use of 'replace', 'retract', and 'excludes' directives in go.mod
- gomodguard # allow and block lists linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations
- goprintffuncname # checks that printf-like functions are named with f at the end
- gosec # inspects source code for security problems
#- lll # reports long lines
- loggercheck # checks key value pairs for common logger libraries (kitlog,klog,logr,zap)
- makezero # finds slice declarations with non-zero initial length
- mirror # reports wrong mirror patterns of bytes/strings usage
- musttag # enforces field tags in (un)marshaled structs
- nakedret # finds naked returns in functions greater than a specified function length
- nestif # reports deeply nested if statements
- nilerr # finds the code that returns nil even if it checks that the error is not nil
#- nilnil # checks that there is no simultaneous return of nil error and an invalid value
- noctx # finds sending http request without context.Context
- nolintlint # reports ill-formed or insufficient nolint directives
#- nonamedreturns # reports all named returns
- nosprintfhostport # checks for misuse of Sprintf to construct a host with port in a URL
#- perfsprint # checks that fmt.Sprintf can be replaced with a faster alternative
- predeclared # finds code that shadows one of Go's predeclared identifiers
- promlinter # checks Prometheus metrics naming via promlint
- protogetter # reports direct reads from proto message fields when getters should be used
- reassign # checks that package variables are not reassigned
- revive # fast, configurable, extensible, flexible, and beautiful linter for Go, drop-in replacement of golint
- rowserrcheck # checks whether Err of rows is checked successfully
- sloglint # ensure consistent code style when using log/slog
- spancheck # checks for mistakes with OpenTelemetry/Census spans
- sqlclosecheck # checks that sql.Rows and sql.Stmt are closed
- stylecheck # is a replacement for golint
- tenv # detects using os.Setenv instead of t.Setenv since Go1.17
- testableexamples # checks if examples are testable (have an expected output)
- testifylint # checks usage of github.com/stretchr/testify
#- testpackage # makes you use a separate _test package
- tparallel # detects inappropriate usage of t.Parallel() method in your Go test codes
- unconvert # removes unnecessary type conversions
#- unparam # reports unused function parameters
- usestdlibvars # detects the possibility to use variables/constants from the Go standard library
- wastedassign # finds wasted assignment statements
- whitespace # detects leading and trailing whitespace
## you may want to enable
#- decorder # checks declaration order and count of types, constants, variables and functions
#- exhaustruct # [highly recommend to enable] checks if all structure fields are initialized
#- gci # controls golang package import order and makes it always deterministic
#- ginkgolinter # [if you use ginkgo/gomega] enforces standards of using ginkgo and gomega
#- godox # detects FIXME, TODO and other comment keywords
#- goheader # checks is file header matches to pattern
#- inamedparam # [great idea, but too strict, need to ignore a lot of cases by default] reports interfaces with unnamed method parameters
#- interfacebloat # checks the number of methods inside an interface
#- ireturn # accept interfaces, return concrete types
#- prealloc # [premature optimization, but can be used in some cases] finds slice declarations that could potentially be preallocated
#- tagalign # checks that struct tags are well aligned
#- varnamelen # [great idea, but too many false positives] checks that the length of a variable's name matches its scope
#- wrapcheck # checks that errors returned from external packages are wrapped
#- zerologlint # detects the wrong usage of zerolog that a user forgets to dispatch zerolog.Event
## disabled
#- containedctx # detects struct contained context.Context field
#- contextcheck # [too many false positives] checks the function whether use a non-inherited context
#- depguard # [replaced by gomodguard] checks if package imports are in a list of acceptable packages
#- dogsled # checks assignments with too many blank identifiers (e.g. x, _, _, _, := f())
#- dupword # [useless without config] checks for duplicate words in the source code
#- errchkjson # [don't see profit + I'm against of omitting errors like in the first example https://github.com/breml/errchkjson] checks types passed to the json encoding functions. Reports unsupported types and optionally reports occasions, where the check for the returned error can be omitted
#- forcetypeassert # [replaced by errcheck] finds forced type assertions
#- goerr113 # [too strict] checks the errors handling expressions
#- gofmt # [replaced by goimports] checks whether code was gofmt-ed
#- gofumpt # [replaced by goimports, gofumports is not available yet] checks whether code was gofumpt-ed
#- gosmopolitan # reports certain i18n/l10n anti-patterns in your Go codebase
#- grouper # analyzes expression groups
#- importas # enforces consistent import aliases
#- maintidx # measures the maintainability index of each function
#- misspell # [useless] finds commonly misspelled English words in comments
#- nlreturn # [too strict and mostly code is not more readable] checks for a new line before return and branch statements to increase code clarity
#- paralleltest # [too many false positives] detects missing usage of t.Parallel() method in your Go test
#- tagliatelle # checks the struct tags
#- thelper # detects golang test helpers without t.Helper() call and checks the consistency of test helpers
#- wsl # [too strict and mostly code is not more readable] whitespace linter forces you to use empty lines
## deprecated
#- deadcode # [deprecated, replaced by unused] finds unused code
#- exhaustivestruct # [deprecated, replaced by exhaustruct] checks if all struct's fields are initialized
#- golint # [deprecated, replaced by revive] golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes
#- ifshort # [deprecated] checks that your code uses short syntax for if-statements whenever possible
#- interfacer # [deprecated] suggests narrower interface types
#- maligned # [deprecated, replaced by govet fieldalignment] detects Go structs that would take less memory if their fields were sorted
#- nosnakecase # [deprecated, replaced by revive var-naming] detects snake case of variable naming and function name
#- scopelint # [deprecated, replaced by exportloopref] checks for unpinned variables in go programs
#- structcheck # [deprecated, replaced by unused] finds unused struct fields
#- varcheck # [deprecated, replaced by unused] finds unused global variables and constants
issues:
# Maximum count of issues with the same text.
# Set to 0 to disable.
# Default: 3
max-same-issues: 50
exclude-rules:
- source: "(noinspection|TODO)"
linters: [ godot ]
- source: "//noinspection"
linters: [ gocritic ]
- path: "_test\\.go"
linters:
- bodyclose
- dupl
- funlen
- goconst
- gosec
- noctx
- wrapcheck
# TODO: remove after PR is released https://github.com/golangci/golangci-lint/pull/4386
- text: "fmt.Sprintf can be replaced with string addition"
linters: [ perfsprint ]
================================================
FILE: .releaserc.json
================================================
{
"debug": true,
"branches": [
"+([0-9])?(.{+([0-9]),x}).x",
"master",
{
"name": "beta",
"prerelease": true
}
],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/github"
]
}
================================================
FILE: CONTRIBUTING.md
================================================
# How to contribute
The following is a set of guidelines for contributing to casbin and its libraries, which are hosted at [casbin organization at Github](https://github.com/casbin).
This project adheres to the [Contributor Covenant 1.2.](https://www.contributor-covenant.org/version/1/2/0/code-of-conduct.html) By participating, you are expected to uphold this code. Please report unacceptable behavior to info@casbin.com.
## Questions
- We do our best to have an [up-to-date documentation](https://casbin.org/docs/overview)
- [Stack Overflow](https://stackoverflow.com) is the best place to start if you have a question. Please use the [casbin tag](https://stackoverflow.com/tags/casbin/info) we are actively monitoring. We encourage you to use Stack Overflow specially for Modeling Access Control Problems, in order to build a shared knowledge base.
- You can also join our [Discord](https://discord.gg/S5UjpzGZjN).
## Reporting issues
Reporting issues are a great way to contribute to the project. We are perpetually grateful about a well-written, through bug report.
Before raising a new issue, check our [issue list](https://github.com/casbin/casbin/issues) to determine if it already contains the problem that you are facing.
A good bug report shouldn't leave others needing to chase you for more information. Please be as detailed as possible. The following questions might serve as a template for writing a detailed report:
What were you trying to achieve?
What are the expected results?
What are the received results?
What are the steps to reproduce the issue?
In what environment did you encounter the issue?
Feature requests can also be submitted as issues.
## Pull requests
Good pull requests (e.g. patches, improvements, new features) are a fantastic help. They should remain focused in scope and avoid unrelated commits.
Please ask first before embarking on any significant pull request (e.g. implementing new features, refactoring code etc.), otherwise you risk spending a lot of time working on something that the maintainers might not want to merge into the project.
First add an issue to the project to discuss the improvement. Please adhere to the coding conventions used throughout the project. If in doubt, consult the [Effective Go style guide](https://golang.org/doc/effective_go.html).
================================================
FILE: DISCLAIMER
================================================
Apache Casbin(Incubating) is an effort undergoing incubation at the Apache Software Foundation (ASF), sponsored by the Apache Incubator PMC.
Incubation is required of all newly accepted projects until a further review indicates that the infrastructure, communications, and decision making process have stabilized in a manner consistent with other successful ASF projects.
While incubation status is not necessarily a reflection of the completeness or stability of the code, it does indicate that the project has yet to be fully endorsed by the ASF.
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
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.
================================================
FILE: Makefile
================================================
SHELL = /bin/bash
export PATH := $(shell yarn global bin):$(PATH)
default: lint test
test:
go test -race -v ./...
benchmark:
go test -bench=.
lint:
golangci-lint run --verbose
release:
npx semantic-release@v19.0.2
================================================
FILE: README.md
================================================
Casbin
====
[](https://goreportcard.com/report/github.com/casbin/casbin)
[](https://github.com/casbin/casbin/actions/workflows/default.yml)
[](https://coveralls.io/github/casbin/casbin?branch=master)
[](https://pkg.go.dev/github.com/casbin/casbin/v2)
[](https://github.com/casbin/casbin/releases/latest)
[](https://discord.gg/S5UjpzGZjN)
[](https://sourcegraph.com/github.com/casbin/casbin?badge)
**News**: still worry about how to write the correct Casbin policy? ``Casbin online editor`` is coming to help! Try it at: https://casbin.org/editor/

Casbin is a powerful and efficient open-source access control library for Golang projects. It provides support for enforcing authorization based on various [access control models](https://en.wikipedia.org/wiki/Computer_security_model).
## All the languages supported by Casbin:
| [](https://github.com/casbin/casbin) | [](https://github.com/casbin/jcasbin) | [](https://github.com/casbin/node-casbin) | [](https://github.com/php-casbin/php-casbin) |
|----------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|
| [Casbin](https://github.com/casbin/casbin) | [jCasbin](https://github.com/casbin/jcasbin) | [node-Casbin](https://github.com/casbin/node-casbin) | [PHP-Casbin](https://github.com/php-casbin/php-casbin) |
| production-ready | production-ready | production-ready | production-ready |
| [](https://github.com/casbin/pycasbin) | [](https://github.com/casbin-net/Casbin.NET) | [](https://github.com/casbin/casbin-cpp) | [](https://github.com/casbin/casbin-rs) |
|------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------|
| [PyCasbin](https://github.com/casbin/pycasbin) | [Casbin.NET](https://github.com/casbin-net/Casbin.NET) | [Casbin-CPP](https://github.com/casbin/casbin-cpp) | [Casbin-RS](https://github.com/casbin/casbin-rs) |
| production-ready | production-ready | production-ready | production-ready |
## Table of contents
- [Supported models](#supported-models)
- [How it works?](#how-it-works)
- [Features](#features)
- [Installation](#installation)
- [Documentation](#documentation)
- [Online editor](#online-editor)
- [Tutorials](#tutorials)
- [Get started](#get-started)
- [Policy management](#policy-management)
- [Policy persistence](#policy-persistence)
- [Policy consistence between multiple nodes](#policy-consistence-between-multiple-nodes)
- [Role manager](#role-manager)
- [Benchmarks](#benchmarks)
- [Examples](#examples)
- [Middlewares](#middlewares)
- [Our adopters](#our-adopters)
## Supported models
1. [**ACL (Access Control List)**](https://en.wikipedia.org/wiki/Access_control_list)
2. **ACL with [superuser](https://en.wikipedia.org/wiki/Superuser)**
3. **ACL without users**: especially useful for systems that don't have authentication or user log-ins.
3. **ACL without resources**: some scenarios may target for a type of resources instead of an individual resource by using permissions like ``write-article``, ``read-log``. It doesn't control the access to a specific article or log.
4. **[RBAC (Role-Based Access Control)](https://en.wikipedia.org/wiki/Role-based_access_control)**
5. **RBAC with resource roles**: both users and resources can have roles (or groups) at the same time.
6. **RBAC with domains/tenants**: users can have different role sets for different domains/tenants.
7. **[ABAC (Attribute-Based Access Control)](https://en.wikipedia.org/wiki/Attribute-Based_Access_Control)**: syntax sugar like ``resource.Owner`` can be used to get the attribute for a resource.
8. **[RESTful](https://en.wikipedia.org/wiki/Representational_state_transfer)**: supports paths like ``/res/*``, ``/res/:id`` and HTTP methods like ``GET``, ``POST``, ``PUT``, ``DELETE``.
9. **Deny-override**: both allow and deny authorizations are supported, deny overrides the allow.
10. **Priority**: the policy rules can be prioritized like firewall rules.
## How it works?
In Casbin, an access control model is abstracted into a CONF file based on the **PERM metamodel (Policy, Effect, Request, Matchers)**. So switching or upgrading the authorization mechanism for a project is just as simple as modifying a configuration. You can customize your own access control model by combining the available models. For example, you can get RBAC roles and ABAC attributes together inside one model and share one set of policy rules.
The most basic and simplest model in Casbin is ACL. ACL's model CONF is:
```ini
# Request definition
[request_definition]
r = sub, obj, act
# Policy definition
[policy_definition]
p = sub, obj, act
# Policy effect
[policy_effect]
e = some(where (p.eft == allow))
# Matchers
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
```
An example policy for ACL model is like:
```
p, alice, data1, read
p, bob, data2, write
```
It means:
- alice can read data1
- bob can write data2
We also support multi-line mode by appending '\\' in the end:
```ini
# Matchers
[matchers]
m = r.sub == p.sub && r.obj == p.obj \
&& r.act == p.act
```
Further more, if you are using ABAC, you can try operator `in` like following in Casbin **golang** edition (jCasbin and Node-Casbin are not supported yet):
```ini
# Matchers
[matchers]
m = r.obj == p.obj && r.act == p.act || r.obj in ('data2', 'data3')
```
But you **SHOULD** make sure that the length of the array is **MORE** than **1**, otherwise there will cause it to panic.
For more operators, you may take a look at [govaluate](https://github.com/casbin/govaluate)
## Features
What Casbin does:
1. enforce the policy in the classic ``{subject, object, action}`` form or a customized form as you defined, both allow and deny authorizations are supported.
2. handle the storage of the access control model and its policy.
3. manage the role-user mappings and role-role mappings (aka role hierarchy in RBAC).
4. support built-in superuser like ``root`` or ``administrator``. A superuser can do anything without explicit permissions.
5. multiple built-in operators to support the rule matching. For example, ``keyMatch`` can map a resource key ``/foo/bar`` to the pattern ``/foo*``.
What Casbin does NOT do:
1. authentication (aka verify ``username`` and ``password`` when a user logs in)
2. manage the list of users or roles. I believe it's more convenient for the project itself to manage these entities. Users usually have their passwords, and Casbin is not designed as a password container. However, Casbin stores the user-role mapping for the RBAC scenario.
## Installation
```
go get github.com/casbin/casbin/v3
```
## Documentation
https://casbin.org/docs/overview
## Online editor
You can also use the online editor (https://casbin.org/editor/) to write your Casbin model and policy in your web browser. It provides functionality such as ``syntax highlighting`` and ``code completion``, just like an IDE for a programming language.
## Tutorials
https://casbin.org/docs/tutorials
## Get started
1. New a Casbin enforcer with a model file and a policy file:
```go
e, _ := casbin.NewEnforcer("path/to/model.conf", "path/to/policy.csv")
```
Note: you can also initialize an enforcer with policy in DB instead of file, see [Policy-persistence](#policy-persistence) section for details.
2. Add an enforcement hook into your code right before the access happens:
```go
sub := "alice" // the user that wants to access a resource.
obj := "data1" // the resource that is going to be accessed.
act := "read" // the operation that the user performs on the resource.
if res, _ := e.Enforce(sub, obj, act); res {
// permit alice to read data1
} else {
// deny the request, show an error
}
```
3. Besides the static policy file, Casbin also provides API for permission management at run-time. For example, You can get all the roles assigned to a user as below:
```go
roles, _ := e.GetImplicitRolesForUser(sub)
```
See [Policy management APIs](#policy-management) for more usage.
## Policy management
Casbin provides two sets of APIs to manage permissions:
- [Management API](https://casbin.org/docs/management-api): the primitive API that provides full support for Casbin policy management.
- [RBAC API](https://casbin.org/docs/rbac-api): a more friendly API for RBAC. This API is a subset of Management API. The RBAC users could use this API to simplify the code.
We also provide a [web-based UI](https://casbin.org/docs/admin-portal) for model management and policy management:


## Policy persistence
https://casbin.org/docs/adapters
## Policy consistence between multiple nodes
https://casbin.org/docs/watchers
## Role manager
https://casbin.org/docs/role-managers
## Benchmarks
https://casbin.org/docs/benchmark
## Examples
| Model | Model file | Policy file |
|---------------------------|----------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------|
| ACL | [basic_model.conf](https://github.com/casbin/casbin/blob/master/examples/basic_model.conf) | [basic_policy.csv](https://github.com/casbin/casbin/blob/master/examples/basic_policy.csv) |
| ACL with superuser | [basic_model_with_root.conf](https://github.com/casbin/casbin/blob/master/examples/basic_with_root_model.conf) | [basic_policy.csv](https://github.com/casbin/casbin/blob/master/examples/basic_policy.csv) |
| ACL without users | [basic_model_without_users.conf](https://github.com/casbin/casbin/blob/master/examples/basic_without_users_model.conf) | [basic_policy_without_users.csv](https://github.com/casbin/casbin/blob/master/examples/basic_without_users_policy.csv) |
| ACL without resources | [basic_model_without_resources.conf](https://github.com/casbin/casbin/blob/master/examples/basic_without_resources_model.conf) | [basic_policy_without_resources.csv](https://github.com/casbin/casbin/blob/master/examples/basic_without_resources_policy.csv) |
| RBAC | [rbac_model.conf](https://github.com/casbin/casbin/blob/master/examples/rbac_model.conf) | [rbac_policy.csv](https://github.com/casbin/casbin/blob/master/examples/rbac_policy.csv) |
| RBAC with resource roles | [rbac_model_with_resource_roles.conf](https://github.com/casbin/casbin/blob/master/examples/rbac_with_resource_roles_model.conf) | [rbac_policy_with_resource_roles.csv](https://github.com/casbin/casbin/blob/master/examples/rbac_with_resource_roles_policy.csv) |
| RBAC with domains/tenants | [rbac_model_with_domains.conf](https://github.com/casbin/casbin/blob/master/examples/rbac_with_domains_model.conf) | [rbac_policy_with_domains.csv](https://github.com/casbin/casbin/blob/master/examples/rbac_with_domains_policy.csv) |
| ABAC | [abac_model.conf](https://github.com/casbin/casbin/blob/master/examples/abac_model.conf) | N/A |
| RESTful | [keymatch_model.conf](https://github.com/casbin/casbin/blob/master/examples/keymatch_model.conf) | [keymatch_policy.csv](https://github.com/casbin/casbin/blob/master/examples/keymatch_policy.csv) |
| Deny-override | [rbac_model_with_deny.conf](https://github.com/casbin/casbin/blob/master/examples/rbac_with_deny_model.conf) | [rbac_policy_with_deny.csv](https://github.com/casbin/casbin/blob/master/examples/rbac_with_deny_policy.csv) |
| Priority | [priority_model.conf](https://github.com/casbin/casbin/blob/master/examples/priority_model.conf) | [priority_policy.csv](https://github.com/casbin/casbin/blob/master/examples/priority_policy.csv) |
## Middlewares
Authz middlewares for web frameworks: https://casbin.org/docs/middlewares
## Our adopters
https://casbin.org/docs/adopters
## How to Contribute
Please read the [contributing guide](CONTRIBUTING.md).
## Contributors
This project exists thanks to all the people who contribute.
<a href="https://github.com/casbin/casbin/graphs/contributors"><img src="https://opencollective.com/casbin/contributors.svg?width=890&button=false" /></a>
## Star History
[](https://star-history.com/#casbin/casbin&Date)
## License
This project is licensed under the [Apache 2.0 license](LICENSE).
## Contact
If you have any issues or feature requests, please contact us. PR is welcomed.
- https://github.com/casbin/casbin/issues
- https://discord.gg/S5UjpzGZjN
================================================
FILE: abac_test.go
================================================
// Copyright 2025 The casbin Authors. All Rights Reserved.
//
// 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 casbin
import (
"encoding/json"
"fmt"
"testing"
"github.com/casbin/casbin/v3/util"
)
type testResource struct {
Name string
Owner string
}
func newTestResource(name string, owner string) testResource {
r := testResource{}
r.Name = name
r.Owner = owner
return r
}
func TestABACModel(t *testing.T) {
e, _ := NewEnforcer("examples/abac_model.conf")
data1 := newTestResource("data1", "alice")
data2 := newTestResource("data2", "bob")
testEnforce(t, e, "alice", data1, "read", true)
testEnforce(t, e, "alice", data1, "write", true)
testEnforce(t, e, "alice", data2, "read", false)
testEnforce(t, e, "alice", data2, "write", false)
testEnforce(t, e, "bob", data1, "read", false)
testEnforce(t, e, "bob", data1, "write", false)
testEnforce(t, e, "bob", data2, "read", true)
testEnforce(t, e, "bob", data2, "write", true)
}
func TestABACMapRequest(t *testing.T) {
e, _ := NewEnforcer("examples/abac_model.conf")
data1 := map[string]interface{}{
"Name": "data1",
"Owner": "alice",
}
data2 := map[string]interface{}{
"Name": "data2",
"Owner": "bob",
}
testEnforce(t, e, "alice", data1, "read", true)
testEnforce(t, e, "alice", data1, "write", true)
testEnforce(t, e, "alice", data2, "read", false)
testEnforce(t, e, "alice", data2, "write", false)
testEnforce(t, e, "bob", data1, "read", false)
testEnforce(t, e, "bob", data1, "write", false)
testEnforce(t, e, "bob", data2, "read", true)
testEnforce(t, e, "bob", data2, "write", true)
}
func TestABACTypes(t *testing.T) {
e, _ := NewEnforcer("examples/abac_model.conf")
matcher := `"moderator" IN r.sub.Roles && r.sub.Enabled == true && r.sub.Age >= 21 && r.sub.Name != "foo"`
e.GetModel()["m"]["m"].Value = util.RemoveComments(util.EscapeAssertion(matcher))
structRequest := struct {
Roles []interface{}
Enabled bool
Age int
Name string
}{
Roles: []interface{}{"user", "moderator"},
Enabled: true,
Age: 30,
Name: "alice",
}
testEnforce(t, e, structRequest, "", "", true)
mapRequest := map[string]interface{}{
"Roles": []interface{}{"user", "moderator"},
"Enabled": true,
"Age": 30,
"Name": "alice",
}
testEnforce(t, e, mapRequest, nil, "", true)
e.EnableAcceptJsonRequest(true)
jsonRequest, _ := json.Marshal(mapRequest)
testEnforce(t, e, string(jsonRequest), "", "", true)
}
func TestABACJsonRequest(t *testing.T) {
e, _ := NewEnforcer("examples/abac_model.conf")
e.EnableAcceptJsonRequest(true)
data1Json := `{ "Name": "data1", "Owner": "alice"}`
data2Json := `{ "Name": "data2", "Owner": "bob"}`
testEnforce(t, e, "alice", data1Json, "read", true)
testEnforce(t, e, "alice", data1Json, "write", true)
testEnforce(t, e, "alice", data2Json, "read", false)
testEnforce(t, e, "alice", data2Json, "write", false)
testEnforce(t, e, "bob", data1Json, "read", false)
testEnforce(t, e, "bob", data1Json, "write", false)
testEnforce(t, e, "bob", data2Json, "read", true)
testEnforce(t, e, "bob", data2Json, "write", true)
e, _ = NewEnforcer("examples/abac_not_using_policy_model.conf", "examples/abac_rule_effect_policy.csv")
e.EnableAcceptJsonRequest(true)
testEnforce(t, e, "alice", data1Json, "read", true)
testEnforce(t, e, "alice", data1Json, "write", true)
testEnforce(t, e, "alice", data2Json, "read", false)
testEnforce(t, e, "alice", data2Json, "write", false)
e, _ = NewEnforcer("examples/abac_rule_model.conf", "examples/abac_rule_policy.csv")
e.EnableAcceptJsonRequest(true)
sub1Json := `{"Name": "alice", "Age": 16}`
sub2Json := `{"Name": "alice", "Age": 20}`
sub3Json := `{"Name": "alice", "Age": 65}`
testEnforce(t, e, sub1Json, "/data1", "read", false)
testEnforce(t, e, sub1Json, "/data2", "read", false)
testEnforce(t, e, sub1Json, "/data1", "write", false)
testEnforce(t, e, sub1Json, "/data2", "write", true)
testEnforce(t, e, sub2Json, "/data1", "read", true)
testEnforce(t, e, sub2Json, "/data2", "read", false)
testEnforce(t, e, sub2Json, "/data1", "write", false)
testEnforce(t, e, sub2Json, "/data2", "write", true)
testEnforce(t, e, sub3Json, "/data1", "read", true)
testEnforce(t, e, sub3Json, "/data2", "read", false)
testEnforce(t, e, sub3Json, "/data1", "write", false)
testEnforce(t, e, sub3Json, "/data2", "write", false)
}
type testSub struct {
Name string
Age int
}
func newTestSubject(name string, age int) testSub {
s := testSub{}
s.Name = name
s.Age = age
return s
}
func TestABACNotUsingPolicy(t *testing.T) {
e, _ := NewEnforcer("examples/abac_not_using_policy_model.conf", "examples/abac_rule_effect_policy.csv")
data1 := newTestResource("data1", "alice")
data2 := newTestResource("data2", "bob")
testEnforce(t, e, "alice", data1, "read", true)
testEnforce(t, e, "alice", data1, "write", true)
testEnforce(t, e, "alice", data2, "read", false)
testEnforce(t, e, "alice", data2, "write", false)
}
func TestABACPolicy(t *testing.T) {
e, _ := NewEnforcer("examples/abac_rule_model.conf", "examples/abac_rule_policy.csv")
m := e.GetModel()
for sec, ast := range m {
fmt.Println(sec)
for ptype, p := range ast {
fmt.Println(ptype, p)
}
}
sub1 := newTestSubject("alice", 16)
sub2 := newTestSubject("alice", 20)
sub3 := newTestSubject("alice", 65)
testEnforce(t, e, sub1, "/data1", "read", false)
testEnforce(t, e, sub1, "/data2", "read", false)
testEnforce(t, e, sub1, "/data1", "write", false)
testEnforce(t, e, sub1, "/data2", "write", true)
testEnforce(t, e, sub2, "/data1", "read", true)
testEnforce(t, e, sub2, "/data2", "read", false)
testEnforce(t, e, sub2, "/data1", "write", false)
testEnforce(t, e, sub2, "/data2", "write", true)
testEnforce(t, e, sub3, "/data1", "read", true)
testEnforce(t, e, sub3, "/data2", "read", false)
testEnforce(t, e, sub3, "/data1", "write", false)
testEnforce(t, e, sub3, "/data2", "write", false)
}
================================================
FILE: ai_api.go
================================================
// Copyright 2026 The casbin Authors. All Rights Reserved.
//
// 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 casbin
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"strings"
"time"
)
// AIConfig contains configuration for AI API calls.
type AIConfig struct {
// Endpoint is the API endpoint (e.g., "https://api.openai.com/v1/chat/completions")
Endpoint string
// APIKey is the authentication key for the API
APIKey string
// Model is the model to use (e.g., "gpt-3.5-turbo", "gpt-4")
Model string
// Timeout for API requests (default: 30s)
Timeout time.Duration
}
// aiMessage represents a message in the OpenAI chat format.
type aiMessage struct {
Role string `json:"role"`
Content string `json:"content"`
}
// aiChatRequest represents the request to OpenAI chat completions API.
type aiChatRequest struct {
Model string `json:"model"`
Messages []aiMessage `json:"messages"`
}
// aiChatResponse represents the response from OpenAI chat completions API.
type aiChatResponse struct {
Choices []struct {
Message aiMessage `json:"message"`
} `json:"choices"`
Error *struct {
Message string `json:"message"`
} `json:"error,omitempty"`
}
// SetAIConfig sets the configuration for AI API calls.
func (e *Enforcer) SetAIConfig(config AIConfig) {
if config.Timeout == 0 {
config.Timeout = 30 * time.Second
}
e.aiConfig = config
}
// Explain returns an AI-generated explanation of why Enforce returned a particular result.
// It calls the configured OpenAI-compatible API to generate a natural language explanation.
func (e *Enforcer) Explain(rvals ...interface{}) (string, error) {
if e.aiConfig.Endpoint == "" {
return "", errors.New("AI config not set, use SetAIConfig first")
}
// Get enforcement result and matched rules
result, matchedRules, err := e.EnforceEx(rvals...)
if err != nil {
return "", fmt.Errorf("failed to enforce: %w", err)
}
// Build context for AI
explainContext := e.buildExplainContext(rvals, result, matchedRules)
// Call AI API
explanation, err := e.callAIAPI(explainContext)
if err != nil {
return "", fmt.Errorf("failed to get AI explanation: %w", err)
}
return explanation, nil
}
// buildExplainContext builds the context string for AI explanation.
func (e *Enforcer) buildExplainContext(rvals []interface{}, result bool, matchedRules []string) string {
var sb strings.Builder
// Add request information
sb.WriteString("Authorization Request:\n")
sb.WriteString(fmt.Sprintf("Subject: %v\n", rvals[0]))
if len(rvals) > 1 {
sb.WriteString(fmt.Sprintf("Object: %v\n", rvals[1]))
}
if len(rvals) > 2 {
sb.WriteString(fmt.Sprintf("Action: %v\n", rvals[2]))
}
sb.WriteString(fmt.Sprintf("\nEnforcement Result: %v\n", result))
// Add matched rules
if len(matchedRules) > 0 {
sb.WriteString("\nMatched Policy Rules:\n")
for _, rule := range matchedRules {
sb.WriteString(fmt.Sprintf("- %s\n", rule))
}
} else {
sb.WriteString("\nNo policy rules matched.\n")
}
// Add model information
sb.WriteString("\nAccess Control Model:\n")
if m, ok := e.model["m"]; ok {
for key, ast := range m {
sb.WriteString(fmt.Sprintf("Matcher (%s): %s\n", key, ast.Value))
}
}
if eff, ok := e.model["e"]; ok {
for key, ast := range eff {
sb.WriteString(fmt.Sprintf("Effect (%s): %s\n", key, ast.Value))
}
}
// Add all policies
policies, _ := e.GetPolicy()
if len(policies) > 0 {
sb.WriteString("\nAll Policy Rules:\n")
for _, policy := range policies {
sb.WriteString(fmt.Sprintf("- %s\n", strings.Join(policy, ", ")))
}
}
return sb.String()
}
// callAIAPI calls the configured AI API to get an explanation.
func (e *Enforcer) callAIAPI(explainContext string) (string, error) {
// Prepare the request
messages := []aiMessage{
{
Role: "system",
Content: "You are an expert in access control and authorization systems. " +
"Explain why an authorization request was allowed or denied based on the " +
"provided access control model, policies, and enforcement result. " +
"Be clear, concise, and educational.",
},
{
Role: "user",
Content: fmt.Sprintf("Please explain the following authorization decision:\n\n%s", explainContext),
},
}
reqBody := aiChatRequest{
Model: e.aiConfig.Model,
Messages: messages,
}
jsonData, err := json.Marshal(reqBody)
if err != nil {
return "", fmt.Errorf("failed to marshal request: %w", err)
}
// Create HTTP request with context
reqCtx, cancel := context.WithTimeout(context.Background(), e.aiConfig.Timeout)
defer cancel()
req, err := http.NewRequestWithContext(reqCtx, http.MethodPost, e.aiConfig.Endpoint, bytes.NewBuffer(jsonData))
if err != nil {
return "", fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+e.aiConfig.APIKey)
// Execute request
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", fmt.Errorf("failed to execute request: %w", err)
}
defer resp.Body.Close()
// Read response
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("failed to read response: %w", err)
}
// Parse response
var chatResp aiChatResponse
if err := json.Unmarshal(body, &chatResp); err != nil {
return "", fmt.Errorf("failed to parse response: %w", err)
}
// Check for API errors
if chatResp.Error != nil {
return "", fmt.Errorf("API error: %s", chatResp.Error.Message)
}
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("API returned status %d: %s", resp.StatusCode, string(body))
}
// Extract explanation
if len(chatResp.Choices) == 0 {
return "", errors.New("no response from AI")
}
return chatResp.Choices[0].Message.Content, nil
}
================================================
FILE: ai_api_test.go
================================================
// Copyright 2026 The casbin Authors. All Rights Reserved.
//
// 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 casbin
import (
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
)
// TestExplainWithoutConfig tests that Explain returns error when config is not set.
func TestExplainWithoutConfig(t *testing.T) {
e, err := NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv")
if err != nil {
t.Fatal(err)
}
_, err = e.Explain("alice", "data1", "read")
if err == nil {
t.Error("Expected error when AI config is not set")
}
if !strings.Contains(err.Error(), "AI config not set") {
t.Errorf("Expected 'AI config not set' error, got: %v", err)
}
}
// TestExplainWithMockAPI tests Explain with a mock OpenAI-compatible API.
func TestExplainWithMockAPI(t *testing.T) {
// Create a mock server that simulates OpenAI API
mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Verify request
if r.Method != http.MethodPost {
t.Errorf("Expected POST request, got %s", r.Method)
}
if r.Header.Get("Content-Type") != "application/json" {
t.Errorf("Expected Content-Type: application/json, got %s", r.Header.Get("Content-Type"))
}
if !strings.HasPrefix(r.Header.Get("Authorization"), "Bearer ") {
t.Errorf("Expected Bearer token in Authorization header, got %s", r.Header.Get("Authorization"))
}
// Parse request to verify structure
var req aiChatRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
t.Errorf("Failed to decode request: %v", err)
}
if req.Model != "gpt-3.5-turbo" {
t.Errorf("Expected model gpt-3.5-turbo, got %s", req.Model)
}
if len(req.Messages) != 2 {
t.Errorf("Expected 2 messages, got %d", len(req.Messages))
}
// Send mock response
resp := aiChatResponse{
Choices: []struct {
Message aiMessage `json:"message"`
}{
{
Message: aiMessage{
Role: "assistant",
Content: "The request was allowed because alice has read permission on data1 according to the policy rule.",
},
},
},
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(resp)
}))
defer mockServer.Close()
// Create enforcer
e, err := NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv")
if err != nil {
t.Fatal(err)
}
// Set AI config with mock server
e.SetAIConfig(AIConfig{
Endpoint: mockServer.URL,
APIKey: "test-api-key",
Model: "gpt-3.5-turbo",
Timeout: 5 * time.Second,
})
// Test explanation for allowed request
explanation, err := e.Explain("alice", "data1", "read")
if err != nil {
t.Fatalf("Failed to get explanation: %v", err)
}
if explanation == "" {
t.Error("Expected non-empty explanation")
}
if !strings.Contains(explanation, "allowed") {
t.Errorf("Expected explanation to mention 'allowed', got: %s", explanation)
}
}
// TestExplainDenied tests Explain for a denied request.
func TestExplainDenied(t *testing.T) {
// Create a mock server
mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
resp := aiChatResponse{
Choices: []struct {
Message aiMessage `json:"message"`
}{
{
Message: aiMessage{
Role: "assistant",
Content: "The request was denied because there is no policy rule that allows alice to write to data1.",
},
},
},
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(resp)
}))
defer mockServer.Close()
// Create enforcer
e, err := NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv")
if err != nil {
t.Fatal(err)
}
// Set AI config
e.SetAIConfig(AIConfig{
Endpoint: mockServer.URL,
APIKey: "test-api-key",
Model: "gpt-3.5-turbo",
Timeout: 5 * time.Second,
})
// Test explanation for denied request
explanation, err := e.Explain("alice", "data1", "write")
if err != nil {
t.Fatalf("Failed to get explanation: %v", err)
}
if explanation == "" {
t.Error("Expected non-empty explanation")
}
if !strings.Contains(explanation, "denied") {
t.Errorf("Expected explanation to mention 'denied', got: %s", explanation)
}
}
// TestExplainAPIError tests handling of API errors.
func TestExplainAPIError(t *testing.T) {
// Create a mock server that returns an error
mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
resp := aiChatResponse{
Error: &struct {
Message string `json:"message"`
}{
Message: "Invalid API key",
},
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusUnauthorized)
json.NewEncoder(w).Encode(resp)
}))
defer mockServer.Close()
// Create enforcer
e, err := NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv")
if err != nil {
t.Fatal(err)
}
// Set AI config
e.SetAIConfig(AIConfig{
Endpoint: mockServer.URL,
APIKey: "invalid-key",
Model: "gpt-3.5-turbo",
Timeout: 5 * time.Second,
})
// Test that API error is properly handled
_, err = e.Explain("alice", "data1", "read")
if err == nil {
t.Error("Expected error for API failure")
}
if !strings.Contains(err.Error(), "Invalid API key") {
t.Errorf("Expected API error message, got: %v", err)
}
}
// TestBuildExplainContext tests the context building function.
func TestBuildExplainContext(t *testing.T) {
e, err := NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv")
if err != nil {
t.Fatal(err)
}
// Test with matched rules
rvals := []interface{}{"alice", "data1", "read"}
result := true
matchedRules := []string{"alice, data1, read"}
context := e.buildExplainContext(rvals, result, matchedRules)
// Verify context contains expected elements
if !strings.Contains(context, "alice") {
t.Error("Context should contain subject 'alice'")
}
if !strings.Contains(context, "data1") {
t.Error("Context should contain object 'data1'")
}
if !strings.Contains(context, "read") {
t.Error("Context should contain action 'read'")
}
if !strings.Contains(context, "true") {
t.Error("Context should contain result 'true'")
}
if !strings.Contains(context, "alice, data1, read") {
t.Error("Context should contain matched rule")
}
// Test with no matched rules
context2 := e.buildExplainContext(rvals, false, []string{})
if !strings.Contains(context2, "No policy rules matched") {
t.Error("Context should indicate no matched rules")
}
}
================================================
FILE: biba_test.go
================================================
// Copyright 2025 The casbin Authors. All Rights Reserved.
//
// 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 casbin
import (
"testing"
)
func testEnforceBiba(t *testing.T, e *Enforcer, sub string, subLevel float64, obj string, objLevel float64, act string, res bool) {
t.Helper()
if myRes, err := e.Enforce(sub, subLevel, obj, objLevel, act); err != nil {
t.Errorf("Enforce Error: %s", err)
} else if myRes != res {
t.Errorf("%s, %v, %s, %v, %s: %t, supposed to be %t", sub, subLevel, obj, objLevel, act, myRes, res)
}
}
func TestBibaModel(t *testing.T) {
e, _ := NewEnforcer("examples/biba_model.conf")
testEnforceBiba(t, e, "alice", 3, "data1", 1, "read", false)
testEnforceBiba(t, e, "bob", 2, "data2", 2, "read", true)
testEnforceBiba(t, e, "charlie", 1, "data1", 1, "read", true)
testEnforceBiba(t, e, "bob", 2, "data3", 3, "read", true)
testEnforceBiba(t, e, "charlie", 1, "data2", 2, "read", true)
testEnforceBiba(t, e, "alice", 3, "data3", 3, "write", true)
testEnforceBiba(t, e, "bob", 2, "data3", 3, "write", false)
testEnforceBiba(t, e, "charlie", 1, "data2", 2, "write", false)
testEnforceBiba(t, e, "alice", 3, "data1", 1, "write", true)
testEnforceBiba(t, e, "bob", 2, "data1", 1, "write", true)
}
================================================
FILE: blp_test.go
================================================
// Copyright 2025 The casbin Authors. All Rights Reserved.
//
// 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 casbin
import (
"testing"
)
func testEnforceBLP(t *testing.T, e *Enforcer, sub string, subLevel float64, obj string, objLevel float64, act string, res bool) {
t.Helper()
if myRes, err := e.Enforce(sub, subLevel, obj, objLevel, act); err != nil {
t.Errorf("Enforce Error: %s", err)
} else if myRes != res {
t.Errorf("%s, %v, %s, %v, %s: %t, supposed to be %t", sub, subLevel, obj, objLevel, act, myRes, res)
}
}
func TestBLPModel(t *testing.T) {
e, _ := NewEnforcer("examples/blp_model.conf")
// Read operations: subject level >= object level
testEnforceBLP(t, e, "alice", 3, "data1", 1, "read", true)
testEnforceBLP(t, e, "bob", 2, "data2", 2, "read", true)
testEnforceBLP(t, e, "charlie", 1, "data1", 1, "read", true)
// Read violations: subject level < object level
testEnforceBLP(t, e, "bob", 2, "data3", 3, "read", false)
testEnforceBLP(t, e, "charlie", 1, "data2", 2, "read", false)
// Write operations: subject level <= object level
testEnforceBLP(t, e, "alice", 3, "data3", 3, "write", true)
testEnforceBLP(t, e, "bob", 2, "data3", 3, "write", true)
testEnforceBLP(t, e, "charlie", 1, "data2", 2, "write", true)
// Write violations: subject level > object level
testEnforceBLP(t, e, "alice", 3, "data1", 1, "write", false)
testEnforceBLP(t, e, "bob", 2, "data1", 1, "write", false)
}
================================================
FILE: config/config.go
================================================
// Copyright 2017 The casbin Authors. All Rights Reserved.
//
// 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 config
import (
"bufio"
"bytes"
"errors"
"fmt"
"io"
"os"
"strconv"
"strings"
)
var (
// DEFAULT_SECTION specifies the name of a section if no name provided.
DEFAULT_SECTION = "default"
// DEFAULT_COMMENT defines what character(s) indicate a comment `#`.
DEFAULT_COMMENT = []byte{'#'}
// DEFAULT_COMMENT_SEM defines what alternate character(s) indicate a comment `;`.
DEFAULT_COMMENT_SEM = []byte{';'}
// DEFAULT_MULTI_LINE_SEPARATOR defines what character indicates a multi-line content.
DEFAULT_MULTI_LINE_SEPARATOR = []byte{'\\'}
)
// ConfigInterface defines the behavior of a Config implementation.
type ConfigInterface interface {
String(key string) string
Strings(key string) []string
Bool(key string) (bool, error)
Int(key string) (int, error)
Int64(key string) (int64, error)
Float64(key string) (float64, error)
Set(key string, value string) error
}
// Config represents an implementation of the ConfigInterface.
type Config struct {
// Section:key=value
data map[string]map[string]string
}
// NewConfig create an empty configuration representation from file.
func NewConfig(confName string) (ConfigInterface, error) {
c := &Config{
data: make(map[string]map[string]string),
}
err := c.parse(confName)
return c, err
}
// NewConfigFromText create an empty configuration representation from text.
func NewConfigFromText(text string) (ConfigInterface, error) {
c := &Config{
data: make(map[string]map[string]string),
}
err := c.parseBuffer(bufio.NewReader(strings.NewReader(text)))
return c, err
}
// AddConfig adds a new section->key:value to the configuration.
func (c *Config) AddConfig(section string, option string, value string) bool {
if section == "" {
section = DEFAULT_SECTION
}
if _, ok := c.data[section]; !ok {
c.data[section] = make(map[string]string)
}
_, ok := c.data[section][option]
c.data[section][option] = value
return !ok
}
func (c *Config) parse(fname string) (err error) {
f, err := os.Open(fname)
if err != nil {
return err
}
defer f.Close()
buf := bufio.NewReader(f)
return c.parseBuffer(buf)
}
func (c *Config) parseBuffer(buf *bufio.Reader) error {
var section string
var lineNum int
var buffer bytes.Buffer
var canWrite bool
for {
if canWrite {
if err := c.write(section, lineNum, &buffer); err != nil {
return err
} else {
canWrite = false
}
}
lineNum++
line, _, err := buf.ReadLine()
if err == io.EOF {
// force write when buffer is not flushed yet
if buffer.Len() > 0 {
if err = c.write(section, lineNum, &buffer); err != nil {
return err
}
}
break
} else if err != nil {
return err
}
line = bytes.TrimSpace(line)
switch {
case bytes.Equal(line, []byte{}), bytes.HasPrefix(line, DEFAULT_COMMENT_SEM),
bytes.HasPrefix(line, DEFAULT_COMMENT):
canWrite = true
continue
case bytes.HasPrefix(line, []byte{'['}) && bytes.HasSuffix(line, []byte{']'}):
// force write when buffer is not flushed yet
if buffer.Len() > 0 {
if err := c.write(section, lineNum, &buffer); err != nil {
return err
}
canWrite = false
}
section = string(line[1 : len(line)-1])
default:
var p []byte
if bytes.HasSuffix(line, DEFAULT_MULTI_LINE_SEPARATOR) {
p = bytes.TrimSpace(line[:len(line)-1])
p = append(p, " "...)
} else {
p = line
canWrite = true
}
end := len(p)
for i, value := range p {
if value == DEFAULT_COMMENT[0] || value == DEFAULT_COMMENT_SEM[0] {
end = i
break
}
}
if _, err := buffer.Write(p[:end]); err != nil {
return err
}
}
}
return nil
}
func (c *Config) write(section string, lineNum int, b *bytes.Buffer) error {
if b.Len() <= 0 {
return nil
}
optionVal := bytes.SplitN(b.Bytes(), []byte{'='}, 2)
if len(optionVal) != 2 {
return fmt.Errorf("parse the content error : line %d , %s = ? ", lineNum, optionVal[0])
}
option := bytes.TrimSpace(optionVal[0])
value := bytes.TrimSpace(optionVal[1])
c.AddConfig(section, string(option), string(value))
// flush buffer after adding
b.Reset()
return nil
}
// Bool lookups up the value using the provided key and converts the value to a bool.
func (c *Config) Bool(key string) (bool, error) {
return strconv.ParseBool(c.get(key))
}
// Int lookups up the value using the provided key and converts the value to a int.
func (c *Config) Int(key string) (int, error) {
return strconv.Atoi(c.get(key))
}
// Int64 lookups up the value using the provided key and converts the value to a int64.
func (c *Config) Int64(key string) (int64, error) {
return strconv.ParseInt(c.get(key), 10, 64)
}
// Float64 lookups up the value using the provided key and converts the value to a float64.
func (c *Config) Float64(key string) (float64, error) {
return strconv.ParseFloat(c.get(key), 64)
}
// String lookups up the value using the provided key and converts the value to a string.
func (c *Config) String(key string) string {
return c.get(key)
}
// Strings lookups up the value using the provided key and converts the value to an array of string
// by splitting the string by comma.
func (c *Config) Strings(key string) []string {
v := c.get(key)
if v == "" {
return nil
}
return strings.Split(v, ",")
}
// Set sets the value for the specific key in the Config.
func (c *Config) Set(key string, value string) error {
if len(key) == 0 {
return errors.New("key is empty")
}
var (
section string
option string
)
keys := strings.Split(strings.ToLower(key), "::")
if len(keys) >= 2 {
section = keys[0]
option = keys[1]
} else {
option = keys[0]
}
c.AddConfig(section, option, value)
return nil
}
// section.key or key.
func (c *Config) get(key string) string {
var (
section string
option string
)
keys := strings.Split(strings.ToLower(key), "::")
if len(keys) >= 2 {
section = keys[0]
option = keys[1]
} else {
section = DEFAULT_SECTION
option = keys[0]
}
if value, ok := c.data[section][option]; ok {
return value
}
return ""
}
================================================
FILE: config/config_test.go
================================================
// Copyright 2017 The casbin Authors. All Rights Reserved.
//
// 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 config
import (
"testing"
)
func TestGet(t *testing.T) {
config, cerr := NewConfig("testdata/testini.ini")
if cerr != nil {
t.Errorf("Configuration file loading failed, err:%v", cerr.Error())
t.Fatalf("err: %v", cerr)
}
// default::key test
if v, err := config.Bool("debug"); err != nil || !v {
t.Errorf("Get failure: expected different value for debug (expected: [%#v] got: [%#v])", true, v)
t.Fatalf("err: %v", err)
}
if v := config.String("url"); v != "act.wiki" {
t.Errorf("Get failure: expected different value for url (expected: [%#v] got: [%#v])", "act.wiki", v)
}
// redis::key test
if v := config.Strings("redis::redis.key"); len(v) != 2 || v[0] != "push1" || v[1] != "push2" {
t.Errorf("Get failure: expected different value for redis::redis.key (expected: [%#v] got: [%#v])", "[]string{push1,push2}", v)
}
if v := config.String("mysql::mysql.dev.host"); v != "127.0.0.1" {
t.Errorf("Get failure: expected different value for mysql::mysql.dev.host (expected: [%#v] got: [%#v])", "127.0.0.1", v)
}
if v := config.String("mysql::mysql.master.host"); v != "10.0.0.1" {
t.Errorf("Get failure: expected different value for mysql::mysql.master.host (expected: [%#v] got: [%#v])", "10.0.0.1", v)
}
if v := config.String("mysql::mysql.master.user"); v != "root" {
t.Errorf("Get failure: expected different value for mysql::mysql.master.user (expected: [%#v] got: [%#v])", "root", v)
}
if v := config.String("mysql::mysql.master.pass"); v != "89dds)2$" {
t.Errorf("Get failure: expected different value for mysql::mysql.master.pass (expected: [%#v] got: [%#v])", "89dds)2$", v)
}
// math::key test
if v, err := config.Int64("math::math.i64"); err != nil || v != 64 {
t.Errorf("Get failure: expected different value for math::math.i64 (expected: [%#v] got: [%#v])", 64, v)
t.Fatalf("err: %v", err)
}
if v, err := config.Float64("math::math.f64"); err != nil || v != 64.1 {
t.Errorf("Get failure: expected different value for math::math.f64 (expected: [%#v] got: [%#v])", 64.1, v)
t.Fatalf("err: %v", err)
}
_ = config.Set("other::key1", "new test key")
if v := config.String("other::key1"); v != "new test key" {
t.Errorf("Get failure: expected different value for other::key1 (expected: [%#v] got: [%#v])", "new test key", v)
}
_ = config.Set("other::key1", "test key")
if v := config.String("multi1::name"); v != "r.sub==p.sub && r.obj==p.obj" {
t.Errorf("Get failure: expected different value for multi1::name (expected: [%#v] got: [%#v])", "r.sub==p.sub&&r.obj==p.obj", v)
}
if v := config.String("multi2::name"); v != "r.sub==p.sub && r.obj==p.obj" {
t.Errorf("Get failure: expected different value for multi2::name (expected: [%#v] got: [%#v])", "r.sub==p.sub&&r.obj==p.obj", v)
}
if v := config.String("multi3::name"); v != "r.sub==p.sub && r.obj==p.obj" {
t.Errorf("Get failure: expected different value for multi3::name (expected: [%#v] got: [%#v])", "r.sub==p.sub&&r.obj==p.obj", v)
}
if v := config.String("multi4::name"); v != "" {
t.Errorf("Get failure: expected different value for multi4::name (expected: [%#v] got: [%#v])", "", v)
}
if v := config.String("multi5::name"); v != "r.sub==p.sub && r.obj==p.obj" {
t.Errorf("Get failure: expected different value for multi5::name (expected: [%#v] got: [%#v])", "r.sub==p.sub&&r.obj==p.obj", v)
}
}
================================================
FILE: config/testdata/testini.ini
================================================
# test config
debug = true
url = act.wiki
; redis config
[redis]
redis.key = push1,push2
; mysql config
[mysql]
mysql.dev.host = 127.0.0.1
mysql.dev.user = root
mysql.dev.pass = 123456
mysql.dev.db = test
mysql.master.host = 10.0.0.1 # host # 10.0.0.1
mysql.master.user = root ; user name
mysql.master.pass = 89dds)2$#d
mysql.master.db = act
; math config
[math]
math.i64 = 64
math.f64 = 64.1
# multi-line test
[multi1]
name = r.sub==p.sub \
&& r.obj==p.obj\
\
[multi2]
name = r.sub==p.sub \
&& r.obj==p.obj
[multi3]
name = r.sub==p.sub \
&& r.obj==p.obj
[multi4]
name = \
\
\
[multi5]
name = r.sub==p.sub \
&& r.obj==p.obj\
\
================================================
FILE: constant/constants.go
================================================
// Copyright 2022 The casbin Authors. All Rights Reserved.
//
// 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 constant
const (
ActionIndex = "act"
DomainIndex = "dom"
SubjectIndex = "sub"
ObjectIndex = "obj"
PriorityIndex = "priority"
)
const (
AllowOverrideEffect = "some(where (p_eft == allow))"
DenyOverrideEffect = "!some(where (p_eft == deny))"
AllowAndDenyEffect = "some(where (p_eft == allow)) && !some(where (p_eft == deny))"
PriorityEffect = "priority(p_eft) || deny"
SubjectPriorityEffect = "subjectPriority(p_eft) || deny"
)
================================================
FILE: constraint_test.go
================================================
// Copyright 2024 The casbin Authors. All Rights Reserved.
//
// 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 casbin
import (
"strings"
"testing"
"github.com/casbin/casbin/v3/errors"
"github.com/casbin/casbin/v3/model"
)
func TestConstraintSOD(t *testing.T) {
modelText := `
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[constraint_definition]
c = sod("role1", "role2")
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
`
m, err := model.NewModelFromString(modelText)
if err != nil {
t.Fatalf("Failed to create model: %v", err)
}
e, err := NewEnforcer(m)
if err != nil {
t.Fatalf("Failed to create enforcer: %v", err)
}
// Add a user to role1 should succeed
_, err = e.AddRoleForUser("alice", "role1")
if err != nil {
t.Fatalf("Failed to add role1 to alice: %v", err)
}
// Add a different user to role2 should succeed
_, err = e.AddRoleForUser("bob", "role2")
if err != nil {
t.Fatalf("Failed to add role2 to bob: %v", err)
}
// Try to add role2 to alice should fail (SOD violation)
_, err = e.AddRoleForUser("alice", "role2")
if err == nil {
t.Fatal("Expected constraint violation error, got nil")
}
if !strings.Contains(err.Error(), "constraint violation") {
t.Fatalf("Expected constraint violation error, got: %v", err)
}
}
func TestConstraintSODMax(t *testing.T) {
modelText := `
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[constraint_definition]
c = sodMax(["role1", "role2", "role3"], 1)
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
`
m, err := model.NewModelFromString(modelText)
if err != nil {
t.Fatalf("Failed to create model: %v", err)
}
e, err := NewEnforcer(m)
if err != nil {
t.Fatalf("Failed to create enforcer: %v", err)
}
// Add user to one role should succeed
_, err = e.AddRoleForUser("alice", "role1")
if err != nil {
t.Fatalf("Failed to add role1 to alice: %v", err)
}
// Try to add user to another role from the set should fail
_, err = e.AddRoleForUser("alice", "role2")
if err == nil {
t.Fatal("Expected constraint violation error, got nil")
}
if !strings.Contains(err.Error(), "constraint violation") {
t.Fatalf("Expected constraint violation error, got: %v", err)
}
}
func TestConstraintRoleMax(t *testing.T) {
modelText := `
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[constraint_definition]
c = roleMax("admin", 2)
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
`
m, err := model.NewModelFromString(modelText)
if err != nil {
t.Fatalf("Failed to create model: %v", err)
}
e, err := NewEnforcer(m)
if err != nil {
t.Fatalf("Failed to create enforcer: %v", err)
}
// Add first user to admin role should succeed
_, err = e.AddRoleForUser("alice", "admin")
if err != nil {
t.Fatalf("Failed to add admin to alice: %v", err)
}
// Add second user to admin role should succeed
_, err = e.AddRoleForUser("bob", "admin")
if err != nil {
t.Fatalf("Failed to add admin to bob: %v", err)
}
// Try to add third user to admin role should fail (exceeds max)
_, err = e.AddRoleForUser("charlie", "admin")
if err == nil {
t.Fatal("Expected constraint violation error, got nil")
}
if !strings.Contains(err.Error(), "constraint violation") {
t.Fatalf("Expected constraint violation error, got: %v", err)
}
}
func TestConstraintRolePre(t *testing.T) {
modelText := `
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[constraint_definition]
c = rolePre("db_admin", "security_trained")
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
`
m, err := model.NewModelFromString(modelText)
if err != nil {
t.Fatalf("Failed to create model: %v", err)
}
e, err := NewEnforcer(m)
if err != nil {
t.Fatalf("Failed to create enforcer: %v", err)
}
// Try to add db_admin without prerequisite should fail
_, err = e.AddRoleForUser("alice", "db_admin")
if err == nil {
t.Fatal("Expected constraint violation error, got nil")
}
if !strings.Contains(err.Error(), "constraint violation") {
t.Fatalf("Expected constraint violation error, got: %v", err)
}
// Add prerequisite role first
_, err = e.AddRoleForUser("alice", "security_trained")
if err != nil {
t.Fatalf("Failed to add security_trained to alice: %v", err)
}
// Now adding db_admin should succeed
_, err = e.AddRoleForUser("alice", "db_admin")
if err != nil {
t.Fatalf("Failed to add db_admin to alice: %v", err)
}
}
func TestConstraintWithoutRBAC(t *testing.T) {
modelText := `
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[constraint_definition]
c = sod("role1", "role2")
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
`
_, err := model.NewModelFromString(modelText)
if err == nil {
t.Fatal("Expected error for constraints without RBAC, got nil")
}
if err != errors.ErrConstraintRequiresRBAC {
t.Fatalf("Expected ErrConstraintRequiresRBAC, got: %v", err)
}
}
func TestConstraintParsingError(t *testing.T) {
modelText := `
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[constraint_definition]
c = invalidFunction("role1", "role2")
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
`
_, err := model.NewModelFromString(modelText)
if err == nil {
t.Fatal("Expected parsing error for invalid constraint, got nil")
}
if !strings.Contains(err.Error(), "constraint parsing error") {
t.Fatalf("Expected constraint parsing error, got: %v", err)
}
}
func TestConstraintRollback(t *testing.T) {
modelText := `
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[constraint_definition]
c = sod("role1", "role2")
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
`
m, err := model.NewModelFromString(modelText)
if err != nil {
t.Fatalf("Failed to create model: %v", err)
}
e, err := NewEnforcer(m)
if err != nil {
t.Fatalf("Failed to create enforcer: %v", err)
}
// Add alice to role1
_, err = e.AddRoleForUser("alice", "role1")
if err != nil {
t.Fatalf("Failed to add role1 to alice: %v", err)
}
// Try to add alice to role2 (should fail with constraint violation)
_, err = e.AddRoleForUser("alice", "role2")
if err == nil {
t.Fatal("Expected constraint violation error, got nil")
}
if !strings.Contains(err.Error(), "constraint violation") {
t.Fatalf("Expected constraint violation error, got: %v", err)
}
}
================================================
FILE: detector/default_detector.go
================================================
// Copyright 2025 The casbin Authors. All Rights Reserved.
//
// 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 detector
import (
"fmt"
"strings"
"github.com/casbin/casbin/v3/rbac"
)
// rangeableRM is an interface for role managers that support iterating over all role links.
// This is used to build the adjacency graph for cycle detection.
type rangeableRM interface {
Range(func(name1, name2 string, domain ...string) bool)
}
// DefaultDetector is the default implementation of the Detector interface.
// It uses depth-first search (DFS) to detect cycles in role inheritance.
type DefaultDetector struct{}
// NewDefaultDetector creates a new instance of DefaultDetector.
func NewDefaultDetector() *DefaultDetector {
return &DefaultDetector{}
}
// Check checks whether the current status of the passed-in RoleManager contains logical errors (e.g., cycles in role inheritance).
// It uses DFS to traverse the role graph and detect cycles.
// Returns nil if no cycle is found, otherwise returns an error with a description of the cycle.
func (d *DefaultDetector) Check(rm rbac.RoleManager) error {
// Defensive nil check to prevent runtime panics
if rm == nil {
return fmt.Errorf("role manager cannot be nil")
}
// Build the adjacency graph by exploring all roles
graph, err := d.buildGraph(rm)
if err != nil {
return err
}
// Run DFS to detect cycles
visited := make(map[string]bool)
recursionStack := make(map[string]bool)
for role := range graph {
if !visited[role] {
if cycle := d.detectCycle(role, graph, visited, recursionStack, []string{}); cycle != nil {
return fmt.Errorf("cycle detected: %s", strings.Join(cycle, " -> "))
}
}
}
return nil
}
// buildGraph builds an adjacency list representation of the role inheritance graph.
// It uses the Range method (via type assertion) to iterate through all role links.
func (d *DefaultDetector) buildGraph(rm rbac.RoleManager) (graph map[string][]string, err error) {
graph = make(map[string][]string)
// Recover from any panics during Range iteration (e.g., nil pointer dereferences)
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("RoleManager is not properly initialized: %v", r)
}
}()
// Try to cast to a RoleManager implementation that supports Range
// This works with RoleManagerImpl and similar implementations
rrm, ok := rm.(rangeableRM)
if !ok {
// Return an error if the RoleManager doesn't support Range iteration
return nil, fmt.Errorf("RoleManager does not support Range iteration, cannot detect cycles")
}
// Use Range method to build the graph directly
rrm.Range(func(name1, name2 string, domain ...string) bool {
// Initialize empty slice for name1 if it doesn't exist
if graph[name1] == nil {
graph[name1] = []string{}
}
// Add the link: name1 -> name2
graph[name1] = append(graph[name1], name2)
// Ensure name2 exists in graph even if it has no outgoing edges
if graph[name2] == nil {
graph[name2] = []string{}
}
return true
})
return graph, nil
}
// detectCycle performs DFS to detect cycles in the role graph.
// Returns a slice representing the cycle path if found, nil otherwise.
func (d *DefaultDetector) detectCycle(
role string,
graph map[string][]string,
visited map[string]bool,
recursionStack map[string]bool,
path []string,
) []string {
// Mark the current role as visited and add to recursion stack
visited[role] = true
recursionStack[role] = true
path = append(path, role)
// Visit all neighbors (parent roles)
for _, neighbor := range graph[role] {
if !visited[neighbor] {
// Recursively visit unvisited neighbor
if cycle := d.detectCycle(neighbor, graph, visited, recursionStack, path); cycle != nil {
return cycle
}
} else if recursionStack[neighbor] {
// Back edge found - cycle detected
// Find where the cycle starts in the path
cycleStart := -1
for i, p := range path {
if p == neighbor {
cycleStart = i
break
}
}
if cycleStart >= 0 {
// Build the cycle path
cyclePath := append([]string{}, path[cycleStart:]...)
cyclePath = append(cyclePath, neighbor)
return cyclePath
}
}
}
// Remove from recursion stack before returning
recursionStack[role] = false
return nil
}
================================================
FILE: detector/default_detector_test.go
================================================
// Copyright 2025 The casbin Authors. All Rights Reserved.
//
// 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 detector
import (
"fmt"
"strings"
"testing"
defaultrolemanager "github.com/casbin/casbin/v3/rbac/default-role-manager"
)
func TestDefaultDetector_NilRoleManager(t *testing.T) {
detector := NewDefaultDetector()
err := detector.Check(nil)
if err == nil {
t.Error("Expected error for nil role manager, but got nil")
} else {
errMsg := err.Error()
if !strings.Contains(errMsg, "role manager cannot be nil") {
t.Errorf("Expected error message to contain 'role manager cannot be nil', got: %s", errMsg)
}
}
}
func TestDefaultDetector_NoCycle(t *testing.T) {
rm := defaultrolemanager.NewRoleManagerImpl(10)
_ = rm.AddLink("alice", "admin")
_ = rm.AddLink("bob", "user")
_ = rm.AddLink("admin", "superuser")
detector := NewDefaultDetector()
err := detector.Check(rm)
if err != nil {
t.Errorf("Expected no cycle, but got error: %v", err)
}
}
func TestDefaultDetector_SimpleCycle(t *testing.T) {
rm := defaultrolemanager.NewRoleManagerImpl(10)
_ = rm.AddLink("A", "B")
_ = rm.AddLink("B", "A")
detector := NewDefaultDetector()
err := detector.Check(rm)
if err == nil {
t.Error("Expected cycle detection error, but got nil")
} else {
errMsg := err.Error()
if !strings.Contains(errMsg, "cycle detected") {
t.Errorf("Expected error message to contain 'Cycle detected', got: %s", errMsg)
}
// Should contain both A and B in the cycle
if !strings.Contains(errMsg, "A") || !strings.Contains(errMsg, "B") {
t.Errorf("Expected error message to contain both A and B, got: %s", errMsg)
}
}
}
func TestDefaultDetector_ComplexCycle(t *testing.T) {
rm := defaultrolemanager.NewRoleManagerImpl(10)
_ = rm.AddLink("A", "B")
_ = rm.AddLink("B", "C")
_ = rm.AddLink("C", "A")
detector := NewDefaultDetector()
err := detector.Check(rm)
if err == nil {
t.Error("Expected cycle detection error, but got nil")
} else {
errMsg := err.Error()
if !strings.Contains(errMsg, "cycle detected") {
t.Errorf("Expected error message to contain 'Cycle detected', got: %s", errMsg)
}
// Should contain A, B, and C in the cycle
if !strings.Contains(errMsg, "A") || !strings.Contains(errMsg, "B") || !strings.Contains(errMsg, "C") {
t.Errorf("Expected error message to contain A, B, and C, got: %s", errMsg)
}
}
}
func TestDefaultDetector_SelfLoop(t *testing.T) {
rm := defaultrolemanager.NewRoleManagerImpl(10)
_ = rm.AddLink("A", "A")
detector := NewDefaultDetector()
err := detector.Check(rm)
if err == nil {
t.Error("Expected cycle detection error for self-loop, but got nil")
} else {
errMsg := err.Error()
if !strings.Contains(errMsg, "cycle detected") {
t.Errorf("Expected error message to contain 'Cycle detected', got: %s", errMsg)
}
}
}
func TestDefaultDetector_MultipleCycles(t *testing.T) {
rm := defaultrolemanager.NewRoleManagerImpl(10)
// First cycle: A -> B -> A
_ = rm.AddLink("A", "B")
_ = rm.AddLink("B", "A")
// Second cycle: C -> D -> C
_ = rm.AddLink("C", "D")
_ = rm.AddLink("D", "C")
detector := NewDefaultDetector()
err := detector.Check(rm)
if err == nil {
t.Error("Expected cycle detection error, but got nil")
} else {
errMsg := err.Error()
if !strings.Contains(errMsg, "cycle detected") {
t.Errorf("Expected error message to contain 'Cycle detected', got: %s", errMsg)
}
}
}
func TestDefaultDetector_DisconnectedComponents(t *testing.T) {
rm := defaultrolemanager.NewRoleManagerImpl(10)
// Component 1: alice -> admin -> superuser
_ = rm.AddLink("alice", "admin")
_ = rm.AddLink("admin", "superuser")
// Component 2: bob -> user
_ = rm.AddLink("bob", "user")
// Component 3: carol -> moderator
_ = rm.AddLink("carol", "moderator")
detector := NewDefaultDetector()
err := detector.Check(rm)
if err != nil {
t.Errorf("Expected no cycle in disconnected components, but got error: %v", err)
}
}
func TestDefaultDetector_ComplexGraphWithCycle(t *testing.T) {
rm := defaultrolemanager.NewRoleManagerImpl(10)
// Build a complex graph with one cycle
_ = rm.AddLink("u1", "g1")
_ = rm.AddLink("u2", "g1")
_ = rm.AddLink("g1", "g2")
_ = rm.AddLink("g2", "g3")
_ = rm.AddLink("g3", "g1") // Creates cycle: g1 -> g2 -> g3 -> g1
_ = rm.AddLink("u3", "g4")
detector := NewDefaultDetector()
err := detector.Check(rm)
if err == nil {
t.Error("Expected cycle detection error, but got nil")
} else {
errMsg := err.Error()
if !strings.Contains(errMsg, "cycle detected") {
t.Errorf("Expected error message to contain 'Cycle detected', got: %s", errMsg)
}
}
}
func TestDefaultDetector_LongCycle(t *testing.T) {
rm := defaultrolemanager.NewRoleManagerImpl(20)
// Create a long cycle: A -> B -> C -> D -> E -> A
_ = rm.AddLink("A", "B")
_ = rm.AddLink("B", "C")
_ = rm.AddLink("C", "D")
_ = rm.AddLink("D", "E")
_ = rm.AddLink("E", "A")
detector := NewDefaultDetector()
err := detector.Check(rm)
if err == nil {
t.Error("Expected cycle detection error, but got nil")
} else {
errMsg := err.Error()
if !strings.Contains(errMsg, "cycle detected") {
t.Errorf("Expected error message to contain 'Cycle detected', got: %s", errMsg)
}
}
}
func TestDefaultDetector_EmptyRoleManager(t *testing.T) {
rm := defaultrolemanager.NewRoleManagerImpl(10)
detector := NewDefaultDetector()
err := detector.Check(rm)
if err != nil {
t.Errorf("Expected no error for empty role manager, but got: %v", err)
}
}
func TestDefaultDetector_LargeGraphNoCycle(t *testing.T) {
rm := defaultrolemanager.NewRoleManagerImpl(100)
// Build a large graph with no cycles: a tree structure
// Create 100 levels: u0 -> u1 -> u2 -> ... -> u99
for i := 0; i < 99; i++ {
user := fmt.Sprintf("u%d", i)
role := fmt.Sprintf("u%d", i+1)
_ = rm.AddLink(user, role)
}
detector := NewDefaultDetector()
err := detector.Check(rm)
if err != nil {
t.Errorf("Expected no cycle in large graph, but got error: %v", err)
}
}
func TestDefaultDetector_LargeGraphWithCycle(t *testing.T) {
rm := defaultrolemanager.NewRoleManagerImpl(100)
// Build a large graph with a cycle at the end
// Create a chain: u0 -> u1 -> u2 -> ... -> u99 -> u0
for i := 0; i < 99; i++ {
user := fmt.Sprintf("u%d", i)
role := fmt.Sprintf("u%d", i+1)
_ = rm.AddLink(user, role)
}
// Add the cycle
_ = rm.AddLink("u99", "u0")
detector := NewDefaultDetector()
err := detector.Check(rm)
if err == nil {
t.Error("Expected cycle detection error in large graph, but got nil")
} else {
errMsg := err.Error()
if !strings.Contains(errMsg, "cycle detected") {
t.Errorf("Expected error message to contain 'Cycle detected', got: %s", errMsg)
}
}
}
// Performance test with 10,000 roles.
func TestDefaultDetector_PerformanceLargeGraph(t *testing.T) {
if testing.Short() {
t.Skip("Skipping performance test in short mode")
}
// Use a higher maxHierarchyLevel to support deep hierarchies
rm := defaultrolemanager.NewRoleManagerImpl(10000)
// Build a large tree structure with 10,000 roles
// Each role has up to 3 children
numRoles := 10000
for i := 0; i < numRoles; i++ {
role := fmt.Sprintf("r%d", i)
// Add links to create a tree structure
child1 := (i * 3) + 1
child2 := (i * 3) + 2
child3 := (i * 3) + 3
if child1 < numRoles {
_ = rm.AddLink(fmt.Sprintf("r%d", child1), role)
}
if child2 < numRoles {
_ = rm.AddLink(fmt.Sprintf("r%d", child2), role)
}
if child3 < numRoles {
_ = rm.AddLink(fmt.Sprintf("r%d", child3), role)
}
}
detector := NewDefaultDetector()
err := detector.Check(rm)
if err != nil {
t.Errorf("Expected no cycle in large performance test, but got error: %v", err)
}
}
func TestDefaultDetector_MultipleInheritance(t *testing.T) {
rm := defaultrolemanager.NewRoleManagerImpl(10)
// User inherits from multiple roles
_ = rm.AddLink("alice", "admin")
_ = rm.AddLink("alice", "moderator")
_ = rm.AddLink("admin", "superuser")
_ = rm.AddLink("moderator", "user")
detector := NewDefaultDetector()
err := detector.Check(rm)
if err != nil {
t.Errorf("Expected no cycle with multiple inheritance, but got error: %v", err)
}
}
func TestDefaultDetector_DiamondPattern(t *testing.T) {
rm := defaultrolemanager.NewRoleManagerImpl(10)
// Diamond pattern: alice -> admin, alice -> moderator, admin -> superuser, moderator -> superuser
_ = rm.AddLink("alice", "admin")
_ = rm.AddLink("alice", "moderator")
_ = rm.AddLink("admin", "superuser")
_ = rm.AddLink("moderator", "superuser")
detector := NewDefaultDetector()
err := detector.Check(rm)
if err != nil {
t.Errorf("Expected no cycle in diamond pattern, but got error: %v", err)
}
}
func TestDefaultDetector_DiamondPatternWithCycle(t *testing.T) {
rm := defaultrolemanager.NewRoleManagerImpl(10)
// Diamond pattern with cycle: alice -> admin, alice -> moderator, admin -> superuser, moderator -> superuser, superuser -> alice
_ = rm.AddLink("alice", "admin")
_ = rm.AddLink("alice", "moderator")
_ = rm.AddLink("admin", "superuser")
_ = rm.AddLink("moderator", "superuser")
_ = rm.AddLink("superuser", "alice") // Creates cycle
detector := NewDefaultDetector()
err := detector.Check(rm)
if err == nil {
t.Error("Expected cycle detection error in diamond pattern with cycle, but got nil")
} else {
errMsg := err.Error()
if !strings.Contains(errMsg, "cycle detected") {
t.Errorf("Expected error message to contain 'Cycle detected', got: %s", errMsg)
}
}
}
================================================
FILE: detector/detector.go
================================================
// Copyright 2025 The casbin Authors. All Rights Reserved.
//
// 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 detector
import "github.com/casbin/casbin/v3/rbac"
// Detector defines the interface of a policy consistency checker, currently used to detect RBAC inheritance cycles.
type Detector interface {
// Check checks whether the current status of the passed-in RoleManager contains logical errors (e.g., cycles in role inheritance).
// param: rm RoleManager instance
// return: If an error is found, return a descriptive error; otherwise return nil.
Check(rm rbac.RoleManager) error
}
================================================
FILE: effector/default_effector.go
================================================
// Copyright 2018 The casbin Authors. All Rights Reserved.
//
// 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 effector
import (
"errors"
"github.com/casbin/casbin/v3/constant"
)
// DefaultEffector is default effector for Casbin.
type DefaultEffector struct {
}
// NewDefaultEffector is the constructor for DefaultEffector.
func NewDefaultEffector() *DefaultEffector {
e := DefaultEffector{}
return &e
}
// MergeEffects merges all matching results collected by the enforcer into a single decision.
func (e *DefaultEffector) MergeEffects(expr string, effects []Effect, matches []float64, policyIndex int, policyLength int) (Effect, int, error) {
result := Indeterminate
explainIndex := -1
switch expr {
case constant.AllowOverrideEffect:
if matches[policyIndex] == 0 {
break
}
// only check the current policyIndex
if effects[policyIndex] == Allow {
result = Allow
explainIndex = policyIndex
break
}
case constant.DenyOverrideEffect:
// only check the current policyIndex
if matches[policyIndex] != 0 && effects[policyIndex] == Deny {
result = Deny
explainIndex = policyIndex
break
}
// if no deny rules are matched at last, then allow
if policyIndex == policyLength-1 {
result = Allow
}
case constant.AllowAndDenyEffect:
// short-circuit if matched deny rule
if matches[policyIndex] != 0 && effects[policyIndex] == Deny {
result = Deny
// set hit rule to the (first) matched deny rule
explainIndex = policyIndex
break
}
// short-circuit some effects in the middle
if policyIndex < policyLength-1 {
// choose not to short-circuit
return result, explainIndex, nil
}
// merge all effects at last
for i, eft := range effects {
if matches[i] == 0 {
continue
}
if eft == Allow {
result = Allow
// set hit rule to first matched allow rule
explainIndex = i
break
}
}
case constant.PriorityEffect, constant.SubjectPriorityEffect:
// reverse merge, short-circuit may be earlier
for i := len(effects) - 1; i >= 0; i-- {
if matches[i] == 0 {
continue
}
if effects[i] != Indeterminate {
if effects[i] == Allow {
result = Allow
} else {
result = Deny
}
explainIndex = i
break
}
}
default:
return Deny, -1, errors.New("unsupported effect")
}
return result, explainIndex, nil
}
================================================
FILE: effector/effector.go
================================================
// Copyright 2018 The casbin Authors. All Rights Reserved.
//
// 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 effector //nolint:cyclop // TODO
// Effect is the result for a policy rule.
type Effect int
// Values for policy effect.
const (
Allow Effect = iota
Indeterminate
Deny
)
// Effector is the interface for Casbin effectors.
type Effector interface {
// MergeEffects merges all matching results collected by the enforcer into a single decision.
MergeEffects(expr string, effects []Effect, matches []float64, policyIndex int, policyLength int) (Effect, int, error)
}
================================================
FILE: enforcer.go
================================================
// Copyright 2017 The casbin Authors. All Rights Reserved.
//
// 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 casbin
import (
"errors"
"fmt"
"runtime/debug"
"strings"
"sync"
"github.com/casbin/casbin/v3/detector"
"github.com/casbin/casbin/v3/effector"
"github.com/casbin/casbin/v3/log"
"github.com/casbin/casbin/v3/model"
"github.com/casbin/casbin/v3/persist"
fileadapter "github.com/casbin/casbin/v3/persist/file-adapter"
"github.com/casbin/casbin/v3/rbac"
defaultrolemanager "github.com/casbin/casbin/v3/rbac/default-role-manager"
"github.com/casbin/casbin/v3/util"
"github.com/casbin/govaluate"
)
// Enforcer is the main interface for authorization enforcement and policy management.
type Enforcer struct {
modelPath string
model model.Model
fm model.FunctionMap
eft effector.Effector
adapter persist.Adapter
watcher persist.Watcher
dispatcher persist.Dispatcher
rmMap map[string]rbac.RoleManager
condRmMap map[string]rbac.ConditionalRoleManager
matcherMap sync.Map
logger log.Logger
detectors []detector.Detector
enabled bool
autoSave bool
autoBuildRoleLinks bool
autoNotifyWatcher bool
autoNotifyDispatcher bool
acceptJsonRequest bool
aiConfig AIConfig
}
// EnforceContext is used as the first element of the parameter "rvals" in method "enforce".
type EnforceContext struct {
RType string
PType string
EType string
MType string
}
func (e EnforceContext) GetCacheKey() string {
return "EnforceContext{" + e.RType + "-" + e.PType + "-" + e.EType + "-" + e.MType + "}"
}
// NewEnforcer creates an enforcer via file or DB.
//
// File:
//
// e := casbin.NewEnforcer("path/to/basic_model.conf", "path/to/basic_policy.csv")
//
// MySQL DB:
//
// a := mysqladapter.NewDBAdapter("mysql", "mysql_username:mysql_password@tcp(127.0.0.1:3306)/")
// e := casbin.NewEnforcer("path/to/basic_model.conf", a)
func NewEnforcer(params ...interface{}) (*Enforcer, error) {
e := &Enforcer{}
parsedParamLen := 0
paramLen := len(params)
switch paramLen - parsedParamLen {
case 2:
switch p0 := params[0].(type) {
case string:
switch p1 := params[1].(type) {
case string:
err := e.InitWithFile(p0, p1)
if err != nil {
return nil, err
}
default:
err := e.InitWithAdapter(p0, p1.(persist.Adapter))
if err != nil {
return nil, err
}
}
default:
switch params[1].(type) {
case string:
return nil, errors.New("invalid parameters for enforcer")
default:
err := e.InitWithModelAndAdapter(p0.(model.Model), params[1].(persist.Adapter))
if err != nil {
return nil, err
}
}
}
case 1:
switch p0 := params[0].(type) {
case string:
err := e.InitWithFile(p0, "")
if err != nil {
return nil, err
}
default:
err := e.InitWithModelAndAdapter(p0.(model.Model), nil)
if err != nil {
return nil, err
}
}
case 0:
return e, nil
default:
return nil, errors.New("invalid parameters for enforcer")
}
return e, nil
}
// InitWithFile initializes an enforcer with a model file and a policy file.
func (e *Enforcer) InitWithFile(modelPath string, policyPath string) error {
a := fileadapter.NewAdapter(policyPath)
return e.InitWithAdapter(modelPath, a)
}
// InitWithAdapter initializes an enforcer with a database adapter.
func (e *Enforcer) InitWithAdapter(modelPath string, adapter persist.Adapter) error {
m, err := model.NewModelFromFile(modelPath)
if err != nil {
return err
}
err = e.InitWithModelAndAdapter(m, adapter)
if err != nil {
return err
}
e.modelPath = modelPath
return nil
}
// InitWithModelAndAdapter initializes an enforcer with a model and a database adapter.
func (e *Enforcer) InitWithModelAndAdapter(m model.Model, adapter persist.Adapter) error {
e.adapter = adapter
e.model = m
e.model.PrintModel()
e.fm = model.LoadFunctionMap()
e.initialize()
// Do not initialize the full policy when using a filtered adapter
fa, ok := e.adapter.(persist.FilteredAdapter)
if e.adapter != nil && (!ok || ok && !fa.IsFiltered()) {
err := e.LoadPolicy()
if err != nil {
return err
}
}
return nil
}
func (e *Enforcer) initialize() {
e.rmMap = map[string]rbac.RoleManager{}
e.condRmMap = map[string]rbac.ConditionalRoleManager{}
e.eft = effector.NewDefaultEffector()
e.watcher = nil
e.matcherMap = sync.Map{}
e.enabled = true
e.autoSave = true
e.autoBuildRoleLinks = true
e.autoNotifyWatcher = true
e.autoNotifyDispatcher = true
e.initRmMap()
// Initialize detectors with default detector if not already set
if e.detectors == nil {
e.detectors = []detector.Detector{detector.NewDefaultDetector()}
}
}
// LoadModel reloads the model from the model CONF file.
// Because the policy is attached to a model, so the policy is invalidated and needs to be reloaded by calling LoadPolicy().
func (e *Enforcer) LoadModel() error {
var err error
e.model, err = model.NewModelFromFile(e.modelPath)
if err != nil {
return err
}
e.model.PrintModel()
e.fm = model.LoadFunctionMap()
e.initialize()
return nil
}
// GetModel gets the current model.
func (e *Enforcer) GetModel() model.Model {
return e.model
}
// SetModel sets the current model.
func (e *Enforcer) SetModel(m model.Model) {
e.model = m
e.fm = model.LoadFunctionMap()
e.initialize()
}
// GetAdapter gets the current adapter.
func (e *Enforcer) GetAdapter() persist.Adapter {
return e.adapter
}
// SetAdapter sets the current adapter.
func (e *Enforcer) SetAdapter(adapter persist.Adapter) {
e.adapter = adapter
}
// SetWatcher sets the current watcher.
func (e *Enforcer) SetWatcher(watcher persist.Watcher) error {
e.watcher = watcher
if _, ok := e.watcher.(persist.WatcherEx); ok {
// The callback of WatcherEx has no generic implementation.
return nil
} else {
// In case the Watcher wants to use a customized callback function, call `SetUpdateCallback` after `SetWatcher`.
return watcher.SetUpdateCallback(func(string) { _ = e.LoadPolicy() })
}
}
// GetRoleManager gets the current role manager.
func (e *Enforcer) GetRoleManager() rbac.RoleManager {
if e.rmMap != nil && e.rmMap["g"] != nil {
return e.rmMap["g"]
} else if e.condRmMap != nil && e.condRmMap["g"] != nil {
return e.condRmMap["g"]
} else {
return nil
}
}
// GetNamedRoleManager gets the role manager for the named policy.
func (e *Enforcer) GetNamedRoleManager(ptype string) rbac.RoleManager {
if e.rmMap != nil && e.rmMap[ptype] != nil {
return e.rmMap[ptype]
} else if e.condRmMap != nil && e.condRmMap[ptype] != nil {
return e.condRmMap[ptype]
} else {
return nil
}
}
// SetRoleManager sets the current role manager.
func (e *Enforcer) SetRoleManager(rm rbac.RoleManager) {
e.invalidateMatcherMap()
e.rmMap["g"] = rm
}
// SetNamedRoleManager sets the role manager for the named policy.
func (e *Enforcer) SetNamedRoleManager(ptype string, rm rbac.RoleManager) {
e.invalidateMatcherMap()
e.rmMap[ptype] = rm
}
// SetEffector sets the current effector.
func (e *Enforcer) SetEffector(eft effector.Effector) {
e.eft = eft
}
// SetLogger sets the logger for the enforcer.
func (e *Enforcer) SetLogger(logger log.Logger) {
e.logger = logger
}
// SetDetector sets a single detector for the enforcer.
func (e *Enforcer) SetDetector(d detector.Detector) {
e.detectors = []detector.Detector{d}
}
// SetDetectors sets multiple detectors for the enforcer.
func (e *Enforcer) SetDetectors(detectors []detector.Detector) {
e.detectors = detectors
}
// RunDetections runs all detectors on all role managers.
// Returns the first error encountered, or nil if all checks pass.
// Silently skips role managers that don't support the required iteration methods.
func (e *Enforcer) RunDetections() error {
if e.detectors == nil || len(e.detectors) == 0 {
return nil
}
// Run detectors on all role managers
for _, rm := range e.rmMap {
for _, d := range e.detectors {
err := d.Check(rm)
// Skip if the role manager doesn't support the required iteration or is not initialized
if err != nil && (strings.Contains(err.Error(), "does not support Range iteration") ||
strings.Contains(err.Error(), "not properly initialized")) {
continue
}
if err != nil {
return err
}
}
}
// Run detectors on all conditional role managers
for _, crm := range e.condRmMap {
for _, d := range e.detectors {
err := d.Check(crm)
// Skip if the role manager doesn't support the required iteration or is not initialized
if err != nil && (strings.Contains(err.Error(), "does not support Range iteration") ||
strings.Contains(err.Error(), "not properly initialized")) {
continue
}
if err != nil {
return err
}
}
}
return nil
}
// ClearPolicy clears all policy.
func (e *Enforcer) ClearPolicy() {
e.invalidateMatcherMap()
if e.dispatcher != nil && e.autoNotifyDispatcher {
_ = e.dispatcher.ClearPolicy()
return
}
e.model.ClearPolicy()
}
// LoadPolicy reloads the policy from file/database.
func (e *Enforcer) LoadPolicy() error {
logEntry := e.onLogBeforeEventInLoadPolicy()
newModel, err := e.loadPolicyFromAdapter(e.model)
if err != nil {
e.onLogAfterEventWithError(logEntry, err)
return err
}
err = e.applyModifiedModel(newModel)
if err != nil {
e.onLogAfterEventWithError(logEntry, err)
return err
}
e.onLogAfterEventInLoadPolicy(logEntry, newModel)
// Run detectors after all policy rules are loaded
err = e.RunDetections()
if err != nil {
return err
}
return nil
}
func (e *Enforcer) loadPolicyFromAdapter(baseModel model.Model) (model.Model, error) {
newModel := baseModel.Copy()
newModel.ClearPolicy()
if err := e.adapter.LoadPolicy(newModel); err != nil && err.Error() != "invalid file path, file path cannot be empty" {
return nil, err
}
if err := newModel.SortPoliciesBySubjectHierarchy(); err != nil {
return nil, err
}
if err := newModel.SortPoliciesByPriority(); err != nil {
return nil, err
}
return newModel, nil
}
func (e *Enforcer) applyModifiedModel(newModel model.Model) error {
var err error
needToRebuild := false
defer func() {
if err != nil {
if e.autoBuildRoleLinks && needToRebuild {
_ = e.BuildRoleLinks()
}
}
}()
if e.autoBuildRoleLinks {
needToRebuild = true
if err := e.rebuildRoleLinks(newModel); err != nil {
return err
}
if err := e.rebuildConditionalRoleLinks(newModel); err != nil {
return err
}
}
e.model = newModel
e.invalidateMatcherMap()
return nil
}
func (e *Enforcer) rebuildRoleLinks(newModel model.Model) error {
if len(e.rmMap) != 0 {
for _, rm := range e.rmMap {
err := rm.Clear()
if err != nil {
return err
}
}
err := newModel.BuildRoleLinks(e.rmMap)
if err != nil {
return err
}
}
return nil
}
func (e *Enforcer) rebuildConditionalRoleLinks(newModel model.Model) error {
if len(e.condRmMap) != 0 {
for _, crm := range e.condRmMap {
err := crm.Clear()
if err != nil {
return err
}
}
err := newModel.BuildConditionalRoleLinks(e.condRmMap)
if err != nil {
return err
}
}
return nil
}
func (e *Enforcer) loadFilteredPolicy(filter interface{}) error {
e.invalidateMatcherMap()
var filteredAdapter persist.FilteredAdapter
// Attempt to cast the Adapter as a FilteredAdapter
switch adapter := e.adapter.(type) {
case persist.FilteredAdapter:
filteredAdapter = adapter
default:
return errors.New("filtered policies are not supported by this adapter")
}
if err := filteredAdapter.LoadFilteredPolicy(e.model, filter); err != nil && err.Error() != "invalid file path, file path cannot be empty" {
return err
}
if err := e.model.SortPoliciesBySubjectHierarchy(); err != nil {
return err
}
if err := e.model.SortPoliciesByPriority(); err != nil {
return err
}
e.initRmMap()
e.model.PrintPolicy()
if e.autoBuildRoleLinks {
err := e.BuildRoleLinks()
if err != nil {
return err
}
}
return nil
}
// LoadFilteredPolicy reloads a filtered policy from file/database.
func (e *Enforcer) LoadFilteredPolicy(filter interface{}) error {
e.model.ClearPolicy()
return e.loadFilteredPolicy(filter)
}
// LoadIncrementalFilteredPolicy append a filtered policy from file/database.
func (e *Enforcer) LoadIncrementalFilteredPolicy(filter interface{}) error {
return e.loadFilteredPolicy(filter)
}
// IsFiltered returns true if the loaded policy has been filtered.
func (e *Enforcer) IsFiltered() bool {
filteredAdapter, ok := e.adapter.(persist.FilteredAdapter)
if !ok {
return false
}
return filteredAdapter.IsFiltered()
}
// SavePolicy saves the current policy (usually after changed with Casbin API) back to file/database.
func (e *Enforcer) SavePolicy() error {
logEntry := e.onLogBeforeEventInSavePolicy()
if e.IsFiltered() {
err := errors.New("cannot save a filtered policy")
e.onLogAfterEventWithError(logEntry, err)
return err
}
if err := e.adapter.SavePolicy(e.model); err != nil {
e.onLogAfterEventWithError(logEntry, err)
return err
}
e.onLogAfterEventInSavePolicy(logEntry)
if e.watcher != nil {
var err error
if watcher, ok := e.watcher.(persist.WatcherEx); ok {
err = watcher.UpdateForSavePolicy(e.model)
} else {
err = e.watcher.Update()
}
return err
}
return nil
}
// getDomainTokens extracts domain token names from request and policy definitions.
// Returns empty strings if tokens cannot be found.
func (e *Enforcer) getDomainTokens() (rDomainToken, pDomainToken string) {
if rAssertion, ok := e.model["r"]["r"]; ok && len(rAssertion.Tokens) > 1 {
rDomainToken = rAssertion.Tokens[1]
}
if pAssertion, ok := e.model["p"]["p"]; ok && len(pAssertion.Tokens) > 1 {
pDomainToken = pAssertion.Tokens[1]
}
return rDomainToken, pDomainToken
}
// registerDomainMatchingFunc registers domain matching function if the matcher uses keyMatch for domains.
func (e *Enforcer) registerDomainMatchingFunc(ptype string) {
// Dynamically detect the domain token name from the model definition.
// In RBAC with domains, the domain is typically the second parameter (index 1)
// in both request and policy definitions (e.g., r = sub, dom, obj, act).
// We extract the actual token names to support arbitrary domain parameter names.
rDomainToken, pDomainToken := e.getDomainTokens()
if rDomainToken == "" || pDomainToken == "" {
return
}
matchFun := fmt.Sprintf("keyMatch(%s, %s)", rDomainToken, pDomainToken)
if strings.Contains(e.model["m"]["m"].Value, matchFun) {
e.AddNamedDomainMatchingFunc(ptype, "g", util.KeyMatch)
}
}
func (e *Enforcer) initRmMap() {
for ptype, assertion := range e.model["g"] {
if rm, ok := e.rmMap[ptype]; ok {
_ = rm.Clear()
continue
}
if len(assertion.Tokens) <= 2 && len(assertion.ParamsTokens) == 0 {
assertion.RM = defaultrolemanager.NewRoleManagerImpl(10)
e.rmMap[ptype] = assertion.RM
}
if len(assertion.Tokens) <= 2 && len(assertion.ParamsTokens) != 0 {
assertion.CondRM = defaultrolemanager.NewConditionalRoleManager(10)
e.condRmMap[ptype] = assertion.CondRM
}
if len(assertion.Tokens) > 2 {
if len(assertion.ParamsTokens) == 0 {
assertion.RM = defaultrolemanager.NewRoleManager(10)
e.rmMap[ptype] = assertion.RM
} else {
assertion.CondRM = defaultrolemanager.NewConditionalDomainManager(10)
e.condRmMap[ptype] = assertion.CondRM
}
e.registerDomainMatchingFunc(ptype)
}
}
}
// EnableEnforce changes the enforcing state of Casbin, when Casbin is disabled, all access will be allowed by the Enforce() function.
func (e *Enforcer) EnableEnforce(enable bool) {
e.enabled = enable
}
// EnableAutoNotifyWatcher controls whether to save a policy rule automatically notify the Watcher when it is added or removed.
func (e *Enforcer) EnableAutoNotifyWatcher(enable bool) {
e.autoNotifyWatcher = enable
}
// EnableAutoNotifyDispatcher controls whether to save a policy rule automatically notify the Dispatcher when it is added or removed.
func (e *Enforcer) EnableAutoNotifyDispatcher(enable bool) {
e.autoNotifyDispatcher = enable
}
// EnableAutoSave controls whether to save a policy rule automatically to the adapter when it is added or removed.
func (e *Enforcer) EnableAutoSave(autoSave bool) {
e.autoSave = autoSave
}
// EnableAutoBuildRoleLinks controls whether to rebuild the role inheritance relations when a role is added or deleted.
func (e *Enforcer) EnableAutoBuildRoleLinks(autoBuildRoleLinks bool) {
e.autoBuildRoleLinks = autoBuildRoleLinks
}
// EnableAcceptJsonRequest controls whether to accept json as a request parameter.
func (e *Enforcer) EnableAcceptJsonRequest(acceptJsonRequest bool) {
e.acceptJsonRequest = acceptJsonRequest
}
// BuildRoleLinks manually rebuild the role inheritance relations.
func (e *Enforcer) BuildRoleLinks() error {
e.invalidateMatcherMap()
if e.rmMap == nil {
return errors.New("rmMap is nil")
}
for _, rm := range e.rmMap {
err := rm.Clear()
if err != nil {
return err
}
}
return e.model.BuildRoleLinks(e.rmMap)
}
// BuildIncrementalRoleLinks provides incremental build the role inheritance relations.
func (e *Enforcer) BuildIncrementalRoleLinks(op model.PolicyOp, ptype string, rules [][]string) error {
e.invalidateMatcherMap()
return e.model.BuildIncrementalRoleLinks(e.rmMap, op, "g", ptype, rules)
}
// BuildIncrementalConditionalRoleLinks provides incremental build the role inheritance relations with conditions.
func (e *Enforcer) BuildIncrementalConditionalRoleLinks(op model.PolicyOp, ptype string, rules [][]string) error {
e.invalidateMatcherMap()
return e.model.BuildIncrementalConditionalRoleLinks(e.condRmMap, op, "g", ptype, rules)
}
// NewEnforceContext Create a default structure based on the suffix.
func NewEnforceContext(suffix string) EnforceContext {
return EnforceContext{
RType: "r" + suffix,
PType: "p" + suffix,
EType: "e" + suffix,
MType: "m" + suffix,
}
}
func (e *Enforcer) invalidateMatcherMap() {
e.matcherMap = sync.Map{}
}
// enforce use a custom matcher to decides whether a "subject" can access a "object" with the operation "action", input parameters are usually: (matcher, sub, obj, act), use model matcher by default when matcher is "".
func (e *Enforcer) enforce(matcher string, explains *[]string, rvals ...interface{}) (ok bool, err error) { //nolint:funlen,cyclop,gocyclo // TODO: reduce function complexity
logEntry := e.onLogBeforeEventInEnforce(rvals)
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("panic: %v\n%s", r, debug.Stack())
if e.logger != nil && logEntry != nil {
logEntry.Error = err
}
}
e.onLogAfterEventInEnforce(logEntry, ok)
}()
if !e.enabled {
return true, nil
}
functions := e.fm.GetFunctions()
if _, ok := e.model["g"]; ok {
for key, ast := range e.model["g"] {
// g must be a normal role definition (ast.RM != nil)
// or a conditional role definition (ast.CondRM != nil)
// ast.RM and ast.CondRM shouldn't be nil at the same time
if ast.RM != nil {
functions[key] = util.GenerateGFunction(ast.RM)
}
if ast.CondRM != nil {
functions[key] = util.GenerateConditionalGFunction(ast.CondRM)
}
}
}
var (
rType = "r"
pType = "p"
eType = "e"
mType = "m"
)
if len(rvals) != 0 {
switch rvals[0].(type) {
case EnforceContext:
enforceContext := rvals[0].(EnforceContext)
rType = enforceContext.RType
pType = enforceContext.PType
eType = enforceContext.EType
mType = enforceContext.MType
rvals = rvals[1:]
default:
break
}
}
var expString string
if matcher == "" {
expString = e.model["m"][mType].Value
} else {
// For custom matchers provided at runtime, escape backslashes in string literals
expString = util.EscapeStringLiterals(util.RemoveComments(util.EscapeAssertion(matcher)))
}
rTokens := make(map[string]int, len(e.model["r"][rType].Tokens))
for i, token := range e.model["r"][rType].Tokens {
rTokens[token] = i
}
pTokens := make(map[string]int, len(e.model["p"][pType].Tokens))
for i, token := range e.model["p"][pType].Tokens {
pTokens[token] = i
}
if e.acceptJsonRequest {
// try to parse all request values from json to map[string]interface{}
for i, rval := range rvals {
switch rval := rval.(type) {
case string:
// Only attempt JSON parsing for strings that look like JSON objects or arrays
if len(rval) > 0 && (rval[0] == '{' || rval[0] == '[') {
var mapValue map[string]interface{}
mapValue, err = util.JsonToMap(rval)
if err != nil {
// Return a clear error when JSON-like string fails to parse
return false, fmt.Errorf("failed to parse JSON parameter at index %d: %w", i, err)
}
rvals[i] = mapValue
}
}
}
}
parameters := enforceParameters{
rTokens: rTokens,
rVals: rvals,
pTokens: pTokens,
}
hasEval := util.HasEval(expString)
if hasEval {
functions["eval"] = generateEvalFunction(functions, ¶meters)
}
var expression *govaluate.EvaluableExpression
expression, err = e.getAndStoreMatcherExpression(hasEval, expString, functions)
if err != nil {
return false, err
}
if len(e.model["r"][rType].Tokens) != len(rvals) {
return false, fmt.Errorf(
"invalid request size: expected %d, got %d, rvals: %v",
len(e.model["r"][rType].Tokens),
len(rvals),
rvals)
}
var policyEffects []effector.Effect
var matcherResults []float64
var effect effector.Effect
var explainIndex int
if policyLen := len(e.model["p"][pType].Policy); policyLen != 0 && strings.Contains(expString, pType+"_") { //nolint:nestif // TODO: reduce function complexity
policyEffects = make([]effector.Effect, policyLen)
matcherResults = make([]float64, policyLen)
for policyIndex, pvals := range e.model["p"][pType].Policy {
// log.LogPrint("Policy Rule: ", pvals)
if len(e.model["p"][pType].Tokens) != len(pvals) {
return false, fmt.Errorf(
"invalid policy size: expected %d, got %d, pvals: %v",
len(e.model["p"][pType].Tokens),
len(pvals),
pvals)
}
parameters.pVals = pvals
result, err := expression.Eval(parameters)
// log.LogPrint("Result: ", result)
if err != nil {
return false, err
}
// set to no-match at first
matcherResults[policyIndex] = 0
switch result := result.(type) {
case bool:
if result {
matcherResults[policyIndex] = 1
}
case float64:
if result != 0 {
matcherResults[policyIndex] = 1
}
default:
return false, errors.New("matcher result should be bool, int or float")
}
if j, ok := parameters.pTokens[pType+"_eft"]; ok {
eft := parameters.pVals[j]
if eft == "allow" {
policyEffects[policyIndex] = effector.Allow
} else if eft == "deny" {
policyEffects[policyIndex] = effector.Deny
} else {
policyEffects[policyIndex] = effector.Indeterminate
}
} else {
policyEffects[policyIndex] = effector.Allow
}
// if e.model["e"]["e"].Value == "priority(p_eft) || deny" {
// break
// }
effect, explainIndex, err = e.eft.MergeEffects(e.model["e"][eType].Value, policyEffects, matcherResults, policyIndex, policyLen)
if err != nil {
return false, err
}
if effect != effector.Indeterminate {
break
}
}
} else {
if hasEval && len(e.model["p"][pType].Policy) == 0 {
return false, errors.New("please make sure rule exists in policy when using eval() in matcher")
}
policyEffects = make([]effector.Effect, 1)
matcherResults = make([]float64, 1)
matcherResults[0] = 1
parameters.pVals = make([]string, len(parameters.pTokens))
result, err := expression.Eval(parameters)
if err != nil {
return false, err
}
if result.(bool) {
policyEffects[0] = effector.Allow
} else {
policyEffects[0] = effector.Indeterminate
}
effect, explainIndex, err = e.eft.MergeEffects(e.model["e"][eType].Value, policyEffects, matcherResults, 0, 1)
if err != nil {
return false, err
}
}
if explains != nil {
if explainIndex != -1 && len(e.model["p"][pType].Policy) > explainIndex {
*explains = e.model["p"][pType].Policy[explainIndex]
}
}
// effect -> result
result := false
if effect == effector.Allow {
result = true
}
return result, nil
}
func (e *Enforcer) getAndStoreMatcherExpression(hasEval bool, expString string, functions map[string]govaluate.ExpressionFunction) (*govaluate.EvaluableExpression, error) {
var expression *govaluate.EvaluableExpression
var err error
var cachedExpression, isPresent = e.matcherMap.Load(expString)
if !hasEval && isPresent {
expression = cachedExpression.(*govaluate.EvaluableExpression)
} else {
expression, err = govaluate.NewEvaluableExpressionWithFunctions(expString, functions)
if err != nil {
return nil, err
}
e.matcherMap.Store(expString, expression)
}
return expression, nil
}
// Enforce decides whether a "subject" can access a "object" with the operation "action", input parameters are usually: (sub, obj, act).
func (e *Enforcer) Enforce(rvals ...interface{}) (bool, error) {
return e.enforce("", nil, rvals...)
}
// EnforceWithMatcher use a custom matcher to decides whether a "subject" can access a "object" with the operation "action", input parameters are usually: (matcher, sub, obj, act), use model matcher by default when matcher is "".
func (e *Enforcer) EnforceWithMatcher(matcher string, rvals ...interface{}) (bool, error) {
return e.enforce(matcher, nil, rvals...)
}
// EnforceEx explain enforcement by informing matched rules.
func (e *Enforcer) EnforceEx(rvals ...interface{}) (bool, []string, error) {
explain := []string{}
result, err := e.enforce("", &explain, rvals...)
return result, explain, err
}
// EnforceExWithMatcher use a custom matcher and explain enforcement by informing matched rules.
func (e *Enforcer) EnforceExWithMatcher(matcher string, rvals ...interface{}) (bool, []string, error) {
explain := []string{}
result, err := e.enforce(matcher, &explain, rvals...)
return result, explain, err
}
// BatchEnforce enforce in batches.
func (e *Enforcer) BatchEnforce(requests [][]interface{}) ([]bool, error) {
var results []bool
for _, request := range requests {
result, err := e.enforce("", nil, request...)
if err != nil {
return results, err
}
results = append(results, result)
}
return results, nil
}
// BatchEnforceWithMatcher enforce with matcher in batches.
func (e *Enforcer) BatchEnforceWithMatcher(matcher string, requests [][]interface{}) ([]bool, error) {
var results []bool
for _, request := range requests {
result, err := e.enforce(matcher, nil, request...)
if err != nil {
return results, err
}
results = append(results, result)
}
return results, nil
}
// AddNamedMatchingFunc add MatchingFunc by ptype RoleManager.
func (e *Enforcer) AddNamedMatchingFunc(ptype, name string, fn rbac.MatchingFunc) bool {
if rm, ok := e.rmMap[ptype]; ok {
rm.AddMatchingFunc(name, fn)
return true
}
return false
}
// AddNamedDomainMatchingFunc add MatchingFunc by ptype to RoleManager.
func (e *Enforcer) AddNamedDomainMatchingFunc(ptype, name string, fn rbac.MatchingFunc) bool {
if rm, ok := e.rmMap[ptype]; ok {
rm.AddDomainMatchingFunc(name, fn)
return true
}
if condRm, ok := e.condRmMap[ptype]; ok {
condRm.AddDomainMatchingFunc(name, fn)
return true
}
return false
}
// AddNamedLinkConditionFunc Add condition function fn for Link userName->roleName,
// when fn returns true, Link is valid, otherwise invalid.
func (e *Enforcer) AddNamedLinkConditionFunc(ptype, user, role string, fn rbac.LinkConditionFunc) bool {
if rm, ok := e.condRmMap[ptype]; ok {
rm.AddLinkConditionFunc(user, role, fn)
return true
}
return false
}
// AddNamedDomainLinkConditionFunc Add condition function fn for Link userName-> {roleName, domain},
// when fn returns true, Link is valid, otherwise invalid.
func (e *Enforcer) AddNamedDomainLinkConditionFunc(ptype, user, role string, domain string, fn rbac.LinkConditionFunc) bool {
if rm, ok := e.condRmMap[ptype]; ok {
rm.AddDomainLinkConditionFunc(user, role, domain, fn)
return true
}
return false
}
// SetNamedLinkConditionFuncParams Sets the parameters of the condition function fn for Link userName->roleName.
func (e *Enforcer) SetNamedLinkConditionFuncParams(ptype, user, role string, params ...string) bool {
if rm, ok := e.condRmMap[ptype]; ok {
rm.SetLinkConditionFuncParams(user, role, params...)
return true
}
return false
}
// SetNamedDomainLinkConditionFuncParams Sets the parameters of the condition function fn
// for Link userName->{roleName, domain}.
func (e *Enforcer) SetNamedDomainLinkConditionFuncParams(ptype, user, role, domain string, params ...string) bool {
if rm, ok := e.condRmMap[ptype]; ok {
rm.SetDomainLinkConditionFuncParams(user, role, domain, params...)
return true
}
return false
}
// assumes bounds have already been checked.
type enforceParameters struct {
rTokens map[string]int
rVals []interface{}
pTokens map[string]int
pVals []string
}
// implements govaluate.Parameters.
func (p enforceParameters) Get(name string) (interface{}, error) {
if name == "" {
return nil, nil
}
switch name[0] {
case 'p':
i, ok := p.pTokens[name]
if !ok {
return nil, errors.New("No parameter '" + name + "' found.")
}
return p.pVals[i], nil
case 'r':
i, ok := p.rTokens[name]
if !ok {
return nil, errors.New("No parameter '" + name + "' found.")
}
return p.rVals[i], nil
default:
return nil, errors.New("No parameter '" + name + "' found.")
}
}
func generateEvalFunction(functions map[string]govaluate.ExpressionFunction, parameters *enforceParameters) govaluate.ExpressionFunction {
return func(args ...interface{}) (interface{}, error) {
if len(args) != 1 {
return nil, fmt.Errorf("function eval(subrule string) expected %d arguments, but got %d", 1, len(args))
}
expression, ok := args[0].(string)
if !ok {
return nil, errors.New("argument of eval(subrule string) must be a string")
}
expression = util.EscapeAssertion(expression)
expr, err := govaluate.NewEvaluableExpressionWithFunctions(expression, functions)
if err != nil {
return nil, fmt.Errorf("error while parsing eval parameter: %s, %s", expression, err.Error())
}
return expr.Eval(parameters)
}
}
================================================
FILE: enforcer_backslash_test.go
================================================
// Copyright 2024 The casbin Authors. All Rights Reserved.
//
// 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 casbin
import (
"testing"
"github.com/casbin/casbin/v3/model"
fileadapter "github.com/casbin/casbin/v3/persist/file-adapter"
)
// TestBackslashHandlingConsistency tests that backslashes in string literals
// within matcher expressions are handled consistently with CSV-parsed values.
// This addresses the issue where govaluate interprets escape sequences in
// string literals, but CSV parsing treats backslashes as literal characters.
func TestBackslashHandlingConsistency(t *testing.T) {
// Test case 1: Literal string in matcher should match CSV-parsed request
t.Run("LiteralInMatcher", func(t *testing.T) {
m := model.NewModel()
m.AddDef("r", "r", "sub, obj, act")
m.AddDef("p", "p", "sub, obj, act")
m.AddDef("e", "e", "some(where (p.eft == allow))")
// User writes '\1\2' in matcher - should be treated as literal backslashes
m.AddDef("m", "m", "regexMatch('\\1\\2', p.obj)")
e, err := NewEnforcer(m, fileadapter.NewAdapter("examples/basic_policy.csv"))
if err != nil {
t.Fatal(err)
}
// Add a policy with a regex pattern containing backslashes
// CSV format: "\\[0-9]+\\" means literal string with 4 backslashes
_, err = e.AddPolicy("filename", "\\\\[0-9]+\\\\", "read")
if err != nil {
t.Fatal(err)
}
// This should match because '\1\2' after escaping becomes \1\2,
// and the pattern \\[0-9]+\\ matches strings like \1\ (which is a substring of \1\2)
result, err := e.Enforce("filename", "dummy", "read")
if err != nil {
t.Fatal(err)
}
if !result {
t.Errorf("Expected true, got false - literal '\\1\\2' should match after escape processing")
}
})
// Test case 2: Request parameter should match policy with same backslash content
t.Run("RequestParameterVsPolicy", func(t *testing.T) {
m := model.NewModel()
m.AddDef("r", "r", "sub, obj, act")
m.AddDef("p", "p", "sub, obj, act")
m.AddDef("e", "e", "some(where (p.eft == allow))")
m.AddDef("m", "m", "regexMatch(r.obj, p.obj)")
e, err := NewEnforcer(m, fileadapter.NewAdapter("examples/basic_policy.csv"))
if err != nil {
t.Fatal(err)
}
// Add policy with regex pattern
_, err = e.AddPolicy("filename", "\\\\[0-9]+\\\\", "read")
if err != nil {
t.Fatal(err)
}
// Request with backslashes - simulating CSV input "\1\2" which becomes \1\2
result, err := e.Enforce("filename", "\\1\\2", "read")
if err != nil {
t.Fatal(err)
}
if !result {
t.Errorf("Expected true, got false - request \\1\\2 should match regex pattern")
}
})
// Test case 3: Both approaches should give the same result
t.Run("ConsistencyBetweenLiteralAndParameter", func(t *testing.T) {
// Create two enforcers with different matchers
m1 := model.NewModel()
m1.AddDef("r", "r", "sub, obj, act")
m1.AddDef("p", "p", "sub, obj, act")
m1.AddDef("e", "e", "some(where (p.eft == allow))")
m1.AddDef("m", "m", "regexMatch('\\1\\2', p.obj)")
m2 := model.NewModel()
m2.AddDef("r", "r", "sub, obj, act")
m2.AddDef("p", "p", "sub, obj, act")
m2.AddDef("e", "e", "some(where (p.eft == allow))")
m2.AddDef("m", "m", "regexMatch(r.obj, p.obj)")
e1, err := NewEnforcer(m1, fileadapter.NewAdapter("examples/basic_policy.csv"))
if err != nil {
t.Fatal(err)
}
e2, err := NewEnforcer(m2, fileadapter.NewAdapter("examples/basic_policy.csv"))
if err != nil {
t.Fatal(err)
}
// Add same policy to both
pattern := "\\\\[0-9]+\\\\"
_, err = e1.AddPolicy("filename", pattern, "read")
if err != nil {
t.Fatal(err)
}
_, err = e2.AddPolicy("filename", pattern, "read")
if err != nil {
t.Fatal(err)
}
// Test with the same request
result1, err := e1.Enforce("filename", "dummy", "read")
if err != nil {
t.Fatal(err)
}
result2, err := e2.Enforce("filename", "\\1\\2", "read")
if err != nil {
t.Fatal(err)
}
if result1 != result2 {
t.Errorf("Inconsistent results: literal in matcher gave %v, parameter gave %v", result1, result2)
}
})
// Test case 4: Simple equality check with backslashes
t.Run("SimpleEqualityWithBackslashes", func(t *testing.T) {
m := model.NewModel()
m.AddDef("r", "r", "sub, obj, act")
m.AddDef("p", "p", "sub, obj, act")
m.AddDef("e", "e", "some(where (p.eft == allow))")
// In Go source, '\test' (one backslash in the actual string) represents
// what would be typed in a web form. After escape processing, it will match
// the CSV-parsed value "\test" (one backslash).
// Note: In Go source, we write "r.obj == '\\test'" which is a Go string
// containing the text: r.obj == '\test' (with ONE backslash in the string content)
m.AddDef("m", "m", "r.obj == '\\test' && p.sub == r.sub")
e, err := NewEnforcer(m, fileadapter.NewAdapter("examples/basic_policy.csv"))
if err != nil {
t.Fatal(err)
}
_, err = e.AddPolicy("alice", "any", "read")
if err != nil {
t.Fatal(err)
}
// Request with literal backslash from CSV would be "\test"
// In Go source, we write "\\test" which represents the string \test (one backslash)
result, err := e.Enforce("alice", "\\test", "read")
if err != nil {
t.Fatal(err)
}
if !result {
t.Errorf("Expected true - literal '\\test' should equal request parameter \\test")
}
})
}
================================================
FILE: enforcer_cached.go
================================================
// Copyright 2018 The casbin Authors. All Rights Reserved.
//
// 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 casbin
import (
"strings"
"sync"
"sync/atomic"
"time"
"github.com/casbin/casbin/v3/persist/cache"
)
// CachedEnforcer wraps Enforcer and provides decision cache.
type CachedEnforcer struct {
*Enforcer
expireTime time.Duration
cache cache.Cache
enableCache int32
locker *sync.RWMutex
}
type CacheableParam interface {
GetCacheKey() string
}
// NewCachedEnforcer creates a cached enforcer via file or DB.
func NewCachedEnforcer(params ...interface{}) (*CachedEnforcer, error) {
e := &CachedEnforcer{}
var err error
e.Enforcer, err = NewEnforcer(params...)
if err != nil {
return nil, err
}
e.enableCache = 1
e.cache, _ = cache.NewDefaultCache()
e.locker = new(sync.RWMutex)
return e, nil
}
// EnableCache determines whether to enable cache on Enforce(). When enableCache is enabled, cached result (true | false) will be returned for previous decisions.
func (e *CachedEnforcer) EnableCache(enableCache bool) {
var enabled int32
if enableCache {
enabled = 1
}
atomic.StoreInt32(&e.enableCache, enabled)
}
// Enforce decides whether a "subject" can access a "object" with the operation "action", input parameters are usually: (sub, obj, act).
// if rvals is not string , ignore the cache.
func (e *CachedEnforcer) Enforce(rvals ...interface{}) (bool, error) {
if atomic.LoadInt32(&e.enableCache) == 0 {
return e.Enforcer.Enforce(rvals...)
}
key, ok := e.getKey(rvals...)
if !ok {
return e.Enforcer.Enforce(rvals...)
}
if res, err := e.getCachedResult(key); err == nil {
return res, nil
} else if err != cache.ErrNoSuchKey {
return res, err
}
res, err := e.Enforcer.Enforce(rvals...)
if err != nil {
return false, err
}
err = e.setCachedResult(key, res, e.expireTime)
return res, err
}
func (e *CachedEnforcer) LoadPolicy() error {
if atomic.LoadInt32(&e.enableCache) != 0 {
if err := e.cache.Clear(); err != nil {
return err
}
}
return e.Enforcer.LoadPolicy()
}
func (e *CachedEnforcer) RemovePolicy(params ...interface{}) (bool, error) {
if atomic.LoadInt32(&e.enableCache) != 0 {
key, ok := e.getKey(params...)
if ok {
if err := e.cache.Delete(key); err != nil && err != cache.ErrNoSuchKey {
return false, err
}
}
}
return e.Enforcer.RemovePolicy(params...)
}
func (e *CachedEnforcer) RemovePolicies(rules [][]string) (bool, error) {
if len(rules) != 0 {
if atomic.LoadInt32(&e.enableCache) != 0 {
irule := make([]interface{}, len(rules[0]))
for _, rule := range rules {
for i, param := range rule {
irule[i] = param
}
key, _ := e.getKey(irule...)
if err := e.cache.Delete(key); err != nil && err != cache.ErrNoSuchKey {
return false, err
}
}
}
}
return e.Enforcer.RemovePolicies(rules)
}
func (e *CachedEnforcer) getCachedResult(key string) (res bool, err error) {
e.locker.Lock()
defer e.locker.Unlock()
return e.cache.Get(key)
}
func (e *CachedEnforcer) SetExpireTime(expireTime time.Duration) {
e.expireTime = expireTime
}
func (e *CachedEnforcer) SetCache(c cache.Cache) {
e.cache = c
}
func (e *CachedEnforcer) setCachedResult(key string, res bool, extra ...interface{}) error {
e.locker.Lock()
defer e.locker.Unlock()
return e.cache.Set(key, res, extra...)
}
func (e *CachedEnforcer) getKey(params ...interface{}) (string, bool) {
return GetCacheKey(params...)
}
// InvalidateCache deletes all the existing cached decisions.
func (e *CachedEnforcer) InvalidateCache() error {
e.locker.Lock()
defer e.locker.Unlock()
return e.cache.Clear()
}
func GetCacheKey(params ...interface{}) (string, bool) {
key := strings.Builder{}
for _, param := range params {
switch typedParam := param.(type) {
case string:
key.WriteString(typedParam)
case CacheableParam:
key.WriteString(typedParam.GetCacheKey())
default:
return "", false
}
key.WriteString("$$")
}
return key.String(), true
}
// ClearPolicy clears all policy.
func (e *CachedEnforcer) ClearPolicy() {
if atomic.LoadInt32(&e.enableCache) != 0 {
if err := e.cache.Clear(); err != nil {
// Logger has been removed - error is ignored
return
}
}
e.Enforcer.ClearPolicy()
}
================================================
FILE: enforcer_cached_b_test.go
================================================
// Copyright 2017 The casbin Authors. All Rights Reserved.
//
// 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 casbin
import (
"fmt"
"testing"
)
func BenchmarkCachedRaw(b *testing.B) {
for i := 0; i < b.N; i++ {
rawEnforce("alice", "data1", "read")
}
}
func BenchmarkCachedBasicModel(b *testing.B) {
e, _ := NewCachedEnforcer("examples/basic_model.conf", "examples/basic_policy.csv")
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = e.Enforce("alice", "data1", "read")
}
}
func BenchmarkCachedRBACModel(b *testing.B) {
e, _ := NewCachedEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv")
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = e.Enforce("alice", "data2", "read")
}
}
func BenchmarkCachedRBACModelSmall(b *testing.B) {
e, _ := NewCachedEnforcer("examples/rbac_model.conf")
// 100 roles, 10 resources.
for i := 0; i < 100; i++ {
_, err := e.AddPolicy(fmt.Sprintf("group%d", i), fmt.Sprintf("data%d", i/10), "read")
if err != nil {
b.Fatal(err)
}
}
// 1000 users.
for i := 0; i < 1000; i++ {
_, err := e.AddGroupingPolicy(fmt.Sprintf("user%d", i), fmt.Sprintf("group%d", i/10))
if err != nil {
b.Fatal(err)
}
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = e.Enforce("user501", "data9", "read")
}
}
func BenchmarkCachedRBACModelMedium(b *testing.B) {
e, _ := NewCachedEnforcer("examples/rbac_model.conf")
// 1000 roles, 100 resources.
pPolicies := make([][]string, 0)
for i := 0; i < 1000; i++ {
pPolicies = append(pPolicies, []string{fmt.Sprintf("group%d", i), fmt.Sprintf("data%d", i/10), "read"})
}
_, err := e.AddPolicies(pPolicies)
if err != nil {
b.Fatal(err)
}
// 10000 users.
gPolicies := make([][]string, 0)
for i := 0; i < 10000; i++ {
gPolicies = append(gPolicies, []string{fmt.Sprintf("user%d", i), fmt.Sprintf("group%d", i/10)})
}
_, err = e.AddGroupingPolicies(gPolicies)
if err != nil {
b.Fatal(err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = e.Enforce("user5001", "data150", "read")
}
}
func BenchmarkCachedRBACModelLarge(b *testing.B) {
e, _ := NewCachedEnforcer("examples/rbac_model.conf")
// 10000 roles, 1000 resources.
pPolicies := make([][]string, 0)
for i := 0; i < 10000; i++ {
pPolicies = append(pPolicies, []string{fmt.Sprintf("group%d", i), fmt.Sprintf("data%d", i/10), "read"})
}
_, err := e.AddPolicies(pPolicies)
if err != nil {
b.Fatal(err)
}
// 100000 users.
gPolicies := make([][]string, 0)
for i := 0; i < 100000; i++ {
gPolicies = append(gPolicies, []string{fmt.Sprintf("user%d", i), fmt.Sprintf("group%d", i/10)})
}
_, err = e.AddGroupingPolicies(gPolicies)
if err != nil {
b.Fatal(err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = e.Enforce("user50001", "data1500", "read")
}
}
func BenchmarkCachedRBACModelWithResourceRoles(b *testing.B) {
e, _ := NewCachedEnforcer("examples/rbac_with_resource_roles_model.conf", "examples/rbac_with_resource_roles_policy.csv")
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = e.Enforce("alice", "data1", "read")
}
}
func BenchmarkCachedRBACModelWithDomains(b *testing.B) {
e, _ := NewCachedEnforcer("examples/rbac_with_domains_model.conf", "examples/rbac_with_domains_policy.csv")
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = e.Enforce("alice", "domain1", "data1", "read")
}
}
func BenchmarkCachedABACModel(b *testing.B) {
e, _ := NewCachedEnforcer("examples/abac_model.conf")
data1 := newTestResource("data1", "alice")
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = e.Enforce("alice", data1, "read")
}
}
func BenchmarkCachedKeyMatchModel(b *testing.B) {
e, _ := NewCachedEnforcer("examples/keymatch_model.conf", "examples/keymatch_policy.csv")
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = e.Enforce("alice", "/alice_data/resource1", "GET")
}
}
func BenchmarkCachedRBACModelWithDeny(b *testing.B) {
e, _ := NewCachedEnforcer("examples/rbac_with_deny_model.conf", "examples/rbac_with_deny_policy.csv")
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = e.Enforce("alice", "data1", "read")
}
}
func BenchmarkCachedPriorityModel(b *testing.B) {
e, _ := NewCachedEnforcer("examples/priority_model.conf", "examples/priority_policy.csv")
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = e.Enforce("alice", "data1", "read")
}
}
func BenchmarkCachedWithEnforceContext(b *testing.B) {
e, _ := NewCachedEnforcer("examples/priority_model_enforce_context.conf", "examples/priority_policy_enforce_context.csv")
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = e.Enforce(EnforceContext{RType: "r2", PType: "p", EType: "e", MType: "m2"}, "alice", "data1")
}
}
func BenchmarkCachedRBACModelMediumParallel(b *testing.B) {
e, _ := NewCachedEnforcer("examples/rbac_model.conf")
// 10000 roles, 1000 resources.
pPolicies := make([][]string, 0)
for i := 0; i < 10000; i++ {
pPolicies = append(pPolicies, []string{fmt.Sprintf("group%d", i), fmt.Sprintf("data%d", i/10), "read"})
}
_, err := e.AddPolicies(pPolicies)
if err != nil {
b.Fatal(err)
}
// 100000 users.
gPolicies := make([][]string, 0)
for i := 0; i < 100000; i++ {
gPolicies = append(gPolicies, []string{fmt.Sprintf("user%d", i), fmt.Sprintf("group%d", i/10)})
}
_, err = e.AddGroupingPolicies(gPolicies)
if err != nil {
b.Fatal(err)
}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_, _ = e.Enforce("user5001", "data150", "read")
}
})
}
================================================
FILE: enforcer_cached_gfunction_test.go
================================================
// Copyright 2017 The casbin Authors. All Rights Reserved.
//
// 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 casbin
import "testing"
// TestCachedGFunctionAfterAddingGroupingPolicy tests that adding new grouping policies
// at runtime correctly updates permission evaluation without requiring a restart or manual cache clearing.
// This is a regression test for the issue where GenerateGFunction's memoization cache
// caused stale permission results after adding new grouping policies.
func TestCachedGFunctionAfterAddingGroupingPolicy(t *testing.T) {
e, err := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv")
if err != nil {
t.Fatalf("Failed to create enforcer: %v", err)
}
// Initial state: bob should not have access to data2 (read)
// bob has no roles initially
ok, err := e.Enforce("bob", "data2", "read")
if err != nil {
t.Fatalf("Enforce failed: %v", err)
}
if ok {
t.Error("bob should not have read access to data2 initially")
}
// Add a new grouping policy: bob becomes data2_admin
// data2_admin has read and write access to data2
_, err = e.AddGroupingPolicy("bob", "data2_admin")
if err != nil {
t.Fatalf("Failed to add grouping policy: %v", err)
}
// Now bob should have read access to data2 through the data2_admin role
// This should work immediately without needing to clear cache or restart
ok, err = e.Enforce("bob", "data2", "read")
if err != nil {
t.Fatalf("Enforce failed after adding grouping policy: %v", err)
}
if !ok {
t.Error("bob should have read access to data2 after being added to data2_admin role")
}
// Also verify write access works
ok, err = e.Enforce("bob", "data2", "write")
if err != nil {
t.Fatalf("Enforce failed: %v", err)
}
if !ok {
t.Error("bob should have write access to data2 after being added to data2_admin role")
}
}
// TestCachedGFunctionWithMultipleEnforceCalls tests that the g() function cache
// properly invalidates when grouping policies change, even after multiple enforce calls.
func TestCachedGFunctionWithMultipleEnforceCalls(t *testing.T) {
e, err := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv")
if err != nil {
t.Fatalf("Failed to create enforcer: %v", err)
}
// Make multiple enforce calls to ensure the g() function closure is cached
for i := 0; i < 5; i++ {
ok, enforceErr := e.Enforce("charlie", "data2", "read")
if enforceErr != nil {
t.Fatalf("Enforce failed on iteration %d: %v", i, enforceErr)
}
if ok {
t.Errorf("charlie should not have read access to data2 on iteration %d", i)
}
}
// Add grouping policy
_, err = e.AddGroupingPolicy("charlie", "data2_admin")
if err != nil {
t.Fatalf("Failed to add grouping policy: %v", err)
}
// Immediately verify the change took effect
ok, err := e.Enforce("charlie", "data2", "read")
if err != nil {
t.Fatalf("Enforce failed after adding grouping policy: %v", err)
}
if !ok {
t.Error("charlie should have read access to data2 immediately after being added to data2_admin role")
}
// Make multiple calls to ensure it stays consistent
for i := 0; i < 5; i++ {
ok, enforceErr := e.Enforce("charlie", "data2", "read")
if enforceErr != nil {
t.Fatalf("Enforce failed on iteration %d after policy change: %v", i, enforceErr)
}
if !ok {
t.Errorf("charlie should have read access to data2 on iteration %d after policy change", i)
}
}
}
// TestCachedGFunctionAfterRemovingGroupingPolicy tests that removing grouping policies
// also properly invalidates the g() function cache.
func TestCachedGFunctionAfterRemovingGroupingPolicy(t *testing.T) {
e, err := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv")
if err != nil {
t.Fatalf("Failed to create enforcer: %v", err)
}
// alice initially has the data2_admin role
ok, err := e.Enforce("alice", "data2", "read")
if err != nil {
t.Fatalf("Enforce failed: %v", err)
}
if !ok {
t.Error("alice should have read access to data2 initially")
}
// Remove alice from data2_admin role
_, err = e.RemoveGroupingPolicy("alice", "data2_admin")
if err != nil {
t.Fatalf("Failed to remove grouping policy: %v", err)
}
// Now alice should not have access to data2 (she only has access to data1)
ok, err = e.Enforce("alice", "data2", "read")
if err != nil {
t.Fatalf("Enforce failed after removing grouping policy: %v", err)
}
if ok {
t.Error("alice should not have read access to data2 after being removed from data2_admin role")
}
// Verify alice still has access to data1 (direct policy)
ok, err = e.Enforce("alice", "data1", "read")
if err != nil {
t.Fatalf("Enforce failed: %v", err)
}
if !ok {
t.Error("alice should still have read access to data1 (direct policy)")
}
}
// TestCachedGFunctionAfterBuildRoleLinks tests the specific scenario mentioned in the bug report:
// adding grouping policies and calling BuildRoleLinks() manually should properly invalidate the cache.
func TestCachedGFunctionAfterBuildRoleLinks(t *testing.T) {
e, err := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv")
if err != nil {
t.Fatalf("Failed to create enforcer: %v", err)
}
// First, make some enforce calls to ensure the g() function closure is created and cached
// This will cache "bob" NOT having data2_admin role in the g() function's sync.Map
for i := 0; i < 3; i++ {
ok, enforceErr := e.Enforce("bob", "data2", "read")
if enforceErr != nil {
t.Fatalf("Enforce failed on iteration %d: %v", i, enforceErr)
}
if ok {
t.Errorf("bob should not have read access to data2 on iteration %d (before adding role)", i)
}
}
// Disable autoBuildRoleLinks to manually control when role links are rebuilt
e.EnableAutoBuildRoleLinks(false)
// Manually add the grouping policy to the model (bypassing BuildIncrementalRoleLinks)
// This simulates the scenario where policies are loaded from database
err = e.model.AddPolicy("g", "g", []string{"bob", "data2_admin"})
if err != nil {
t.Fatalf("Failed to add grouping policy to model: %v", err)
}
// Manually build role links as mentioned in the issue
// This is the key part - BuildRoleLinks() should invalidate the matcher map cache
err = e.BuildRoleLinks()
if err != nil {
t.Fatalf("Failed to build role links: %v", err)
}
// Now bob should have read access to data2 through the data2_admin role
// This is where the bug would manifest - if BuildRoleLinks() doesn't invalidate the cache,
// the old g() function closure with "bob->data2_admin = false" cached will still be used
ok, err := e.Enforce("bob", "data2", "read")
if err != nil {
t.Fatalf("Enforce failed after BuildRoleLinks: %v", err)
}
if !ok {
t.Error("bob should have read access to data2 after BuildRoleLinks() - this indicates the g() function cache was not properly invalidated")
}
}
================================================
FILE: enforcer_cached_synced.go
================================================
// Copyright 2018 The casbin Authors. All Rights Reserved.
//
// 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 casbin
import (
"sync"
"sync/atomic"
"time"
"github.com/casbin/casbin/v3/persist/cache"
)
// SyncedCachedEnforcer wraps Enforcer and provides decision sync cache.
type SyncedCachedEnforcer struct {
*SyncedEnforcer
expireTime time.Duration
cache cache.Cache
enableCache int32
locker *sync.RWMutex
}
// NewSyncedCachedEnforcer creates a sync cached enforcer via file or DB.
func NewSyncedCachedEnforcer(params ...interface{}) (*SyncedCachedEnforcer, error) {
e := &SyncedCachedEnforcer{}
var err error
e.SyncedEnforcer, err = NewSyncedEnforcer(params...)
if err != nil {
return nil, err
}
e.enableCache = 1
e.cache, _ = cache.NewSyncCache()
e.locker = new(sync.RWMutex)
return e, nil
}
// EnableCache determines whether to enable cache on Enforce(). When enableCache is enabled, cached result (true | false) will be returned for previous decisions.
func (e *SyncedCachedEnforcer) EnableCache(enableCache bool) {
var enabled int32
if enableCache {
enabled = 1
}
atomic.StoreInt32(&e.enableCache, enabled)
}
// Enforce decides whether a "subject" can access a "object" with the operation "action", input parameters are usually: (sub, obj, act).
// if rvals is not string , ignore the cache.
func (e *SyncedCachedEnforcer) Enforce(rvals ...interface{}) (bool, error) {
if atomic.LoadInt32(&e.enableCache) == 0 {
return e.SyncedEnforcer.Enforce(rvals...)
}
key, ok := e.getKey(rvals...)
if !ok {
return e.SyncedEnforcer.Enforce(rvals...)
}
if res, err := e.getCachedResult(key); err == nil {
return res, nil
} else if err != cache.ErrNoSuchKey {
return res, err
}
res, err := e.SyncedEnforcer.Enforce(rvals...)
if err != nil {
return false, err
}
err = e.setCachedResult(key, res, e.expireTime)
return res, err
}
func (e *SyncedCachedEnforcer) LoadPolicy() error {
if atomic.LoadInt32(&e.enableCache) != 0 {
if err := e.cache.Clear(); err != nil {
return err
}
}
return e.SyncedEnforcer.LoadPolicy()
}
func (e *SyncedCachedEnforcer) AddPolicy(params ...interface{}) (bool, error) {
if ok, err := e.checkOneAndRemoveCache(params...); !ok {
return ok, err
}
return e.SyncedEnforcer.AddPolicy(params...)
}
func (e *SyncedCachedEnforcer) AddPolicies(rules [][]string) (bool, error) {
if ok, err := e.checkManyAndRemoveCache(rules); !ok {
return ok, err
}
return e.SyncedEnforcer.AddPolicies(rules)
}
func (e *SyncedCachedEnforcer) RemovePolicy(params ...interface{}) (bool, error) {
if ok, err := e.checkOneAndRemoveCache(params...); !ok {
return ok, err
}
return e.SyncedEnforcer.RemovePolicy(params...)
}
func (e *SyncedCachedEnforcer) RemovePolicies(rules [][]string) (bool, error) {
if ok, err := e.checkManyAndRemoveCache(rules); !ok {
return ok, err
}
return e.SyncedEnforcer.RemovePolicies(rules)
}
func (e *SyncedCachedEnforcer) getCachedResult(key string) (res bool, err error) {
return e.cache.Get(key)
}
func (e *SyncedCachedEnforcer) SetExpireTime(expireTime time.Duration) {
e.locker.Lock()
defer e.locker.Unlock()
e.expireTime = expireTime
}
// SetCache need to be sync cache.
func (e *SyncedCachedEnforcer) SetCache(c cache.Cache) {
e.locker.Lock()
defer e.locker.Unlock()
e.cache = c
}
func (e *SyncedCachedEnforcer) setCachedResult(key string, res bool, extra ...interface{}) error {
return e.cache.Set(key, res, extra...)
}
func (e *SyncedCachedEnforcer) getKey(params ...interface{}) (string, bool) {
return GetCacheKey(params...)
}
// InvalidateCache deletes all the existing cached decisions.
func (e *SyncedCachedEnforcer) InvalidateCache() error {
return e.cache.Clear()
}
func (e *SyncedCachedEnforcer) checkOneAndRemoveCache(params ...interface{}) (bool, error) {
if atomic.LoadInt32(&e.enableCache) != 0 {
key, ok := e.getKey(params...)
if ok {
if err := e.cache.Delete(key); err != nil && err != cache.ErrNoSuchKey {
return false, err
}
}
}
return true, nil
}
func (e *SyncedCachedEnforcer) checkManyAndRemoveCache(rules [][]string) (bool, error) {
if len(rules) != 0 {
if atomic.LoadInt32(&e.enableCache) != 0 {
irule := make([]interface{}, len(rules[0]))
for _, rule := range rules {
for i, param := range rule {
irule[i] = param
}
key, _ := e.getKey(irule...)
if err := e.cache.Delete(key); err != nil && err != cache.ErrNoSuchKey {
return false, err
}
}
}
}
return true, nil
}
================================================
FILE: enforcer_cached_synced_test.go
================================================
// Copyright 2018 The casbin Authors. All Rights Reserved.
//
// 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 casbin
import (
"sync"
"testing"
"time"
)
func testSyncEnforceCache(t *testing.T, e *SyncedCachedEnforcer, sub string, obj interface{}, act string, res bool) {
t.Helper()
if myRes, _ := e.Enforce(sub, obj, act); myRes != res {
t.Errorf("%s, %v, %s: %t, supposed to be %t", sub, obj, act, myRes, res)
}
}
func TestSyncCache(t *testing.T) {
e, _ := NewSyncedCachedEnforcer("examples/basic_model.conf", "examples/basic_policy.csv")
e.expireTime = time.Millisecond
// The cache is enabled by default for NewCachedEnforcer.
g := sync.WaitGroup{}
goThread := 1000
g.Add(goThread)
for i := 0; i < goThread; i++ {
go func() {
_, _ = e.AddPolicy("alice", "data2", "read")
testSyncEnforceCache(t, e, "alice", "data2", "read", true)
if e.InvalidateCache() != nil {
panic("never reached")
}
g.Done()
}()
}
g.Wait()
_, _ = e.RemovePolicy("alice", "data2", "read")
testSyncEnforceCache(t, e, "alice", "data1", "read", true)
time.Sleep(time.Millisecond * 2) // coverage for expire
testSyncEnforceCache(t, e, "alice", "data1", "read", true)
testSyncEnforceCache(t, e, "alice", "data1", "write", false)
testSyncEnforceCache(t, e, "alice", "data2", "read", false)
testSyncEnforceCache(t, e, "alice", "data2", "write", false)
// The cache is enabled, calling RemovePolicy, LoadPolicy or RemovePolicies will
// also operate cached items.
_, _ = e.RemovePolicy("alice", "data1", "read")
testSyncEnforceCache(t, e, "alice", "data1", "read", false)
testSyncEnforceCache(t, e, "alice", "data1", "write", false)
testSyncEnforceCache(t, e, "alice", "data2", "read", false)
testSyncEnforceCache(t, e, "alice", "data2", "write", false)
e, _ = NewSyncedCachedEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv")
testSyncEnforceCache(t, e, "alice", "data1", "read", true)
testSyncEnforceCache(t, e, "bob", "data2", "write", true)
testSyncEnforceCache(t, e, "alice", "data2", "read", true)
testSyncEnforceCache(t, e, "alice", "data2", "write", true)
_, _ = e.RemovePolicies([][]string{
{"alice", "data1", "read"},
{"bob", "data2", "write"},
})
testSyncEnforceCache(t, e, "alice", "data1", "read", false)
testSyncEnforceCache(t, e, "bob", "data2", "write", false)
testSyncEnforceCache(t, e, "alice", "data2", "read", true)
testSyncEnforceCache(t, e, "alice", "data2", "write", true)
}
================================================
FILE: enforcer_cached_test.go
================================================
// Copyright 2018 The casbin Authors. All Rights Reserved.
//
// 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 casbin
import "testing"
func testEnforceCache(t *testing.T, e *CachedEnforcer, sub string, obj interface{}, act string, res bool) {
t.Helper()
if myRes, _ := e.Enforce(sub, obj, act); myRes != res {
t.Errorf("%s, %v, %s: %t, supposed to be %t", sub, obj, act, myRes, res)
}
}
func TestCache(t *testing.T) {
e, _ := NewCachedEnforcer("examples/basic_model.conf", "examples/basic_policy.csv")
// The cache is enabled by default for NewCachedEnforcer.
testEnforceCache(t, e, "alice", "data1", "read", true)
testEnforceCache(t, e, "alice", "data1", "write", false)
testEnforceCache(t, e, "alice", "data2", "read", false)
testEnforceCache(t, e, "alice", "data2", "write", false)
// The cache is enabled, calling RemovePolicy, LoadPolicy or RemovePolicies will
// also operate cached items.
_, _ = e.RemovePolicy("alice", "data1", "read")
testEnforceCache(t, e, "alice", "data1", "read", false)
testEnforceCache(t, e, "alice", "data1", "write", false)
testEnforceCache(t, e, "alice", "data2", "read", false)
testEnforceCache(t, e, "alice", "data2", "write", false)
e, _ = NewCachedEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv")
testEnforceCache(t, e, "alice", "data1", "read", true)
testEnforceCache(t, e, "bob", "data2", "write", true)
testEnforceCache(t, e, "alice", "data2", "read", true)
testEnforceCache(t, e, "alice", "data2", "write", true)
_, _ = e.RemovePolicies([][]string{
{"alice", "data1", "read"},
{"bob", "data2", "write"},
})
testEnforceCache(t, e, "alice", "data1", "read", false)
testEnforceCache(t, e, "bob", "data2", "write", false)
testEnforceCache(t, e, "alice", "data2", "read", true)
testEnforceCache(t, e, "alice", "data2", "write", true)
e, _ = NewCachedEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv")
testEnforceCache(t, e, "alice", "data1", "read", true)
testEnforceCache(t, e, "bob", "data2", "write", true)
testEnforceCache(t, e, "alice", "data2", "read", true)
testEnforceCache(t, e, "alice", "data2", "write", true)
e.ClearPolicy()
testEnforceCache(t, e, "alice", "data1", "read", false)
gitextract_1o8_iigh/ ├── .asf.yaml ├── .github/ │ ├── scripts/ │ │ ├── benchmark_formatter.py │ │ ├── download_artifact.js │ │ └── post_comment.js │ ├── semantic.yml │ └── workflows/ │ ├── comment.yml │ ├── default.yml │ ├── golangci-lint.yml │ └── performance-pr.yml ├── .gitignore ├── .golangci.yml ├── .releaserc.json ├── CONTRIBUTING.md ├── DISCLAIMER ├── LICENSE ├── Makefile ├── README.md ├── abac_test.go ├── ai_api.go ├── ai_api_test.go ├── biba_test.go ├── blp_test.go ├── config/ │ ├── config.go │ ├── config_test.go │ └── testdata/ │ └── testini.ini ├── constant/ │ └── constants.go ├── constraint_test.go ├── detector/ │ ├── default_detector.go │ ├── default_detector_test.go │ └── detector.go ├── effector/ │ ├── default_effector.go │ └── effector.go ├── enforcer.go ├── enforcer_backslash_test.go ├── enforcer_cached.go ├── enforcer_cached_b_test.go ├── enforcer_cached_gfunction_test.go ├── enforcer_cached_synced.go ├── enforcer_cached_synced_test.go ├── enforcer_cached_test.go ├── enforcer_context.go ├── enforcer_context_interface.go ├── enforcer_context_test.go ├── enforcer_distributed.go ├── enforcer_interface.go ├── enforcer_json_test.go ├── enforcer_synced.go ├── enforcer_synced_test.go ├── enforcer_test.go ├── enforcer_transactional.go ├── error_test.go ├── errors/ │ ├── constraint_errors.go │ └── rbac_errors.go ├── examples/ │ ├── abac_model.conf │ ├── abac_not_using_policy_model.conf │ ├── abac_rule_effect_policy.csv │ ├── abac_rule_model.conf │ ├── abac_rule_policy.csv │ ├── basic_inverse_policy.csv │ ├── basic_model.conf │ ├── basic_model_without_spaces.conf │ ├── basic_policy.csv │ ├── basic_with_root_model.conf │ ├── basic_without_resources_model.conf │ ├── basic_without_resources_policy.csv │ ├── basic_without_users_model.conf │ ├── basic_without_users_policy.csv │ ├── biba_model.conf │ ├── blp_model.conf │ ├── comment_model.conf │ ├── error/ │ │ ├── error_model.conf │ │ └── error_policy.csv │ ├── eval_operator_model.conf │ ├── eval_operator_policy.csv │ ├── glob_model.conf │ ├── glob_policy.csv │ ├── ipmatch_model.conf │ ├── ipmatch_policy.csv │ ├── keyget2_model.conf │ ├── keyget_model.conf │ ├── keymatch2_model.conf │ ├── keymatch2_policy.csv │ ├── keymatch_custom_model.conf │ ├── keymatch_model.conf │ ├── keymatch_policy.csv │ ├── keymatch_with_rbac_in_domain.conf │ ├── keymatch_with_rbac_in_domain.csv │ ├── lbac_model.conf │ ├── multiple_policy_definitions_model.conf │ ├── multiple_policy_definitions_policy.csv │ ├── object_conditions_model.conf │ ├── object_conditions_policy.csv │ ├── orbac_model.conf │ ├── orbac_policy.csv │ ├── pbac_model.conf │ ├── pbac_policy.csv │ ├── performance/ │ │ ├── rbac_with_pattern_large_scale_model.conf │ │ └── rbac_with_pattern_large_scale_policy.csv │ ├── priority_indeterminate_policy.csv │ ├── priority_model.conf │ ├── priority_model_enforce_context.conf │ ├── priority_model_explicit.conf │ ├── priority_model_explicit_customized.conf │ ├── priority_policy.csv │ ├── priority_policy_enforce_context.csv │ ├── priority_policy_explicit.csv │ ├── priority_policy_explicit_customized.csv │ ├── rbac_model.conf │ ├── rbac_model_in_multi_line.conf │ ├── rbac_model_matcher_using_in_op.conf │ ├── rbac_model_matcher_using_in_op_bracket.conf │ ├── rbac_policy.csv │ ├── rbac_with_all_pattern_model.conf │ ├── rbac_with_all_pattern_policy.csv │ ├── rbac_with_constraints_model.conf │ ├── rbac_with_cycle_policy.csv │ ├── rbac_with_deny_model.conf │ ├── rbac_with_deny_policy.csv │ ├── rbac_with_different_types_of_roles_model.conf │ ├── rbac_with_different_types_of_roles_policy.csv │ ├── rbac_with_domain_pattern_model.conf │ ├── rbac_with_domain_pattern_policy.csv │ ├── rbac_with_domain_temporal_roles_model.conf │ ├── rbac_with_domain_temporal_roles_policy.csv │ ├── rbac_with_domains_conditional_model.conf │ ├── rbac_with_domains_conditional_policy.csv │ ├── rbac_with_domains_model.conf │ ├── rbac_with_domains_policy.csv │ ├── rbac_with_domains_policy2.csv │ ├── rbac_with_hierarchy_policy.csv │ ├── rbac_with_hierarchy_with_domains_policy.csv │ ├── rbac_with_multiple_policy_model.conf │ ├── rbac_with_multiple_policy_policy.csv │ ├── rbac_with_not_deny_model.conf │ ├── rbac_with_pattern_model.conf │ ├── rbac_with_pattern_policy.csv │ ├── rbac_with_resource_roles_model.conf │ ├── rbac_with_resource_roles_policy.csv │ ├── rbac_with_temporal_roles_model.conf │ ├── rbac_with_temporal_roles_policy.csv │ ├── rebac_model.conf │ ├── rebac_policy.csv │ ├── subject_priority_model.conf │ ├── subject_priority_model_with_domain.conf │ ├── subject_priority_policy.csv │ ├── subject_priority_policy_with_domain.csv │ └── syntax_matcher_model.conf ├── filter_test.go ├── frontend.go ├── frontend_old.go ├── frontend_old_test.go ├── frontend_test.go ├── go.mod ├── go.sum ├── internal_api.go ├── lbac_test.go ├── log/ │ ├── default_logger.go │ ├── logger.go │ └── types.go ├── logger_test.go ├── management_api.go ├── management_api_b_test.go ├── management_api_test.go ├── model/ │ ├── assertion.go │ ├── constraint.go │ ├── function.go │ ├── model.go │ ├── model_test.go │ └── policy.go ├── model_b_test.go ├── model_test.go ├── orbac_test.go ├── pbac_test.go ├── persist/ │ ├── adapter.go │ ├── adapter_context.go │ ├── adapter_filtered.go │ ├── adapter_filtered_context.go │ ├── batch_adapter.go │ ├── batch_adapter_context.go │ ├── cache/ │ │ ├── cache.go │ │ ├── cache_sync.go │ │ └── default-cache.go │ ├── dispatcher.go │ ├── file-adapter/ │ │ ├── adapter.go │ │ ├── adapter_context.go │ │ ├── adapter_filtered.go │ │ ├── adapter_filtered_context.go │ │ └── adapter_mock.go │ ├── persist_test.go │ ├── string-adapter/ │ │ ├── adapter.go │ │ ├── adapter_context.go │ │ └── adapter_test.go │ ├── transaction.go │ ├── update_adapter.go │ ├── update_adapter_context.go │ ├── watcher.go │ ├── watcher_ex.go │ └── watcher_update.go ├── rbac/ │ ├── context_role_manager.go │ ├── default-role-manager/ │ │ ├── role_manager.go │ │ └── role_manager_test.go │ └── role_manager.go ├── rbac_api.go ├── rbac_api_context.go ├── rbac_api_synced.go ├── rbac_api_test.go ├── rbac_api_with_domains.go ├── rbac_api_with_domains_context.go ├── rbac_api_with_domains_synced.go ├── rbac_api_with_domains_test.go ├── role_manager_b_test.go ├── syntax_test.go ├── transaction.go ├── transaction_buffer.go ├── transaction_commit.go ├── transaction_conflict.go ├── transaction_test.go ├── util/ │ ├── builtin_operators.go │ ├── builtin_operators_test.go │ ├── util.go │ └── util_test.go ├── util_log.go ├── watcher_ex_test.go ├── watcher_test.go └── watcher_update_test.go
SYMBOL INDEX (1396 symbols across 111 files)
FILE: .github/scripts/benchmark_formatter.py
function strip_worker_suffix (line 12) | def strip_worker_suffix(text: str) -> str:
function get_icon (line 15) | def get_icon(diff_val: float) -> str:
function clean_superscripts (line 22) | def clean_superscripts(text: str) -> str:
function parse_val (line 25) | def parse_val(token: str):
function extract_two_numbers (line 64) | def extract_two_numbers(tokens):
function append_aligned (line 182) | def append_aligned(left_part, content):
FILE: abac_test.go
type testResource (line 25) | type testResource struct
function newTestResource (line 30) | func newTestResource(name string, owner string) testResource {
function TestABACModel (line 37) | func TestABACModel(t *testing.T) {
function TestABACMapRequest (line 53) | func TestABACMapRequest(t *testing.T) {
function TestABACTypes (line 75) | func TestABACTypes(t *testing.T) {
function TestABACJsonRequest (line 106) | func TestABACJsonRequest(t *testing.T) {
type testSub (line 150) | type testSub struct
function newTestSubject (line 155) | func newTestSubject(name string, age int) testSub {
function TestABACNotUsingPolicy (line 162) | func TestABACNotUsingPolicy(t *testing.T) {
function TestABACPolicy (line 173) | func TestABACPolicy(t *testing.T) {
FILE: ai_api.go
type AIConfig (line 30) | type AIConfig struct
type aiMessage (line 42) | type aiMessage struct
type aiChatRequest (line 48) | type aiChatRequest struct
type aiChatResponse (line 54) | type aiChatResponse struct
method SetAIConfig (line 64) | func (e *Enforcer) SetAIConfig(config AIConfig) {
method Explain (line 73) | func (e *Enforcer) Explain(rvals ...interface{}) (string, error) {
method buildExplainContext (line 97) | func (e *Enforcer) buildExplainContext(rvals []interface{}, result bool,...
method callAIAPI (line 147) | func (e *Enforcer) callAIAPI(explainContext string) (string, error) {
FILE: ai_api_test.go
function TestExplainWithoutConfig (line 27) | func TestExplainWithoutConfig(t *testing.T) {
function TestExplainWithMockAPI (line 43) | func TestExplainWithMockAPI(t *testing.T) {
function TestExplainDenied (line 121) | func TestExplainDenied(t *testing.T) {
function TestExplainAPIError (line 173) | func TestExplainAPIError(t *testing.T) {
function TestBuildExplainContext (line 215) | func TestBuildExplainContext(t *testing.T) {
FILE: biba_test.go
function testEnforceBiba (line 21) | func testEnforceBiba(t *testing.T, e *Enforcer, sub string, subLevel flo...
function TestBibaModel (line 30) | func TestBibaModel(t *testing.T) {
FILE: blp_test.go
function testEnforceBLP (line 21) | func testEnforceBLP(t *testing.T, e *Enforcer, sub string, subLevel floa...
function TestBLPModel (line 30) | func TestBLPModel(t *testing.T) {
FILE: config/config.go
type ConfigInterface (line 40) | type ConfigInterface interface
type Config (line 51) | type Config struct
method AddConfig (line 75) | func (c *Config) AddConfig(section string, option string, value string...
method parse (line 90) | func (c *Config) parse(fname string) (err error) {
method parseBuffer (line 101) | func (c *Config) parseBuffer(buf *bufio.Reader) error {
method write (line 169) | func (c *Config) write(section string, lineNum int, b *bytes.Buffer) e...
method Bool (line 189) | func (c *Config) Bool(key string) (bool, error) {
method Int (line 194) | func (c *Config) Int(key string) (int, error) {
method Int64 (line 199) | func (c *Config) Int64(key string) (int64, error) {
method Float64 (line 204) | func (c *Config) Float64(key string) (float64, error) {
method String (line 209) | func (c *Config) String(key string) string {
method Strings (line 215) | func (c *Config) Strings(key string) []string {
method Set (line 224) | func (c *Config) Set(key string, value string) error {
method get (line 247) | func (c *Config) get(key string) string {
function NewConfig (line 57) | func NewConfig(confName string) (ConfigInterface, error) {
function NewConfigFromText (line 66) | func NewConfigFromText(text string) (ConfigInterface, error) {
FILE: config/config_test.go
function TestGet (line 21) | func TestGet(t *testing.T) {
FILE: constant/constants.go
constant ActionIndex (line 18) | ActionIndex = "act"
constant DomainIndex (line 19) | DomainIndex = "dom"
constant SubjectIndex (line 20) | SubjectIndex = "sub"
constant ObjectIndex (line 21) | ObjectIndex = "obj"
constant PriorityIndex (line 22) | PriorityIndex = "priority"
constant AllowOverrideEffect (line 26) | AllowOverrideEffect = "some(where (p_eft == allow))"
constant DenyOverrideEffect (line 27) | DenyOverrideEffect = "!some(where (p_eft == deny))"
constant AllowAndDenyEffect (line 28) | AllowAndDenyEffect = "some(where (p_eft == allow)) && !some(where (p_...
constant PriorityEffect (line 29) | PriorityEffect = "priority(p_eft) || deny"
constant SubjectPriorityEffect (line 30) | SubjectPriorityEffect = "subjectPriority(p_eft) || deny"
FILE: constraint_test.go
function TestConstraintSOD (line 25) | func TestConstraintSOD(t *testing.T) {
function TestConstraintSODMax (line 78) | func TestConstraintSODMax(t *testing.T) {
function TestConstraintRoleMax (line 125) | func TestConstraintRoleMax(t *testing.T) {
function TestConstraintRolePre (line 178) | func TestConstraintRolePre(t *testing.T) {
function TestConstraintWithoutRBAC (line 231) | func TestConstraintWithoutRBAC(t *testing.T) {
function TestConstraintParsingError (line 258) | func TestConstraintParsingError(t *testing.T) {
function TestConstraintRollback (line 288) | func TestConstraintRollback(t *testing.T) {
FILE: detector/default_detector.go
type rangeableRM (line 26) | type rangeableRM interface
type DefaultDetector (line 32) | type DefaultDetector struct
method Check (line 42) | func (d *DefaultDetector) Check(rm rbac.RoleManager) error {
method buildGraph (line 71) | func (d *DefaultDetector) buildGraph(rm rbac.RoleManager) (graph map[s...
method detectCycle (line 109) | func (d *DefaultDetector) detectCycle(
function NewDefaultDetector (line 35) | func NewDefaultDetector() *DefaultDetector {
FILE: detector/default_detector_test.go
function TestDefaultDetector_NilRoleManager (line 25) | func TestDefaultDetector_NilRoleManager(t *testing.T) {
function TestDefaultDetector_NoCycle (line 39) | func TestDefaultDetector_NoCycle(t *testing.T) {
function TestDefaultDetector_SimpleCycle (line 53) | func TestDefaultDetector_SimpleCycle(t *testing.T) {
function TestDefaultDetector_ComplexCycle (line 75) | func TestDefaultDetector_ComplexCycle(t *testing.T) {
function TestDefaultDetector_SelfLoop (line 98) | func TestDefaultDetector_SelfLoop(t *testing.T) {
function TestDefaultDetector_MultipleCycles (line 115) | func TestDefaultDetector_MultipleCycles(t *testing.T) {
function TestDefaultDetector_DisconnectedComponents (line 137) | func TestDefaultDetector_DisconnectedComponents(t *testing.T) {
function TestDefaultDetector_ComplexGraphWithCycle (line 155) | func TestDefaultDetector_ComplexGraphWithCycle(t *testing.T) {
function TestDefaultDetector_LongCycle (line 178) | func TestDefaultDetector_LongCycle(t *testing.T) {
function TestDefaultDetector_EmptyRoleManager (line 200) | func TestDefaultDetector_EmptyRoleManager(t *testing.T) {
function TestDefaultDetector_LargeGraphNoCycle (line 211) | func TestDefaultDetector_LargeGraphNoCycle(t *testing.T) {
function TestDefaultDetector_LargeGraphWithCycle (line 230) | func TestDefaultDetector_LargeGraphWithCycle(t *testing.T) {
function TestDefaultDetector_PerformanceLargeGraph (line 257) | func TestDefaultDetector_PerformanceLargeGraph(t *testing.T) {
function TestDefaultDetector_MultipleInheritance (line 293) | func TestDefaultDetector_MultipleInheritance(t *testing.T) {
function TestDefaultDetector_DiamondPattern (line 309) | func TestDefaultDetector_DiamondPattern(t *testing.T) {
function TestDefaultDetector_DiamondPatternWithCycle (line 325) | func TestDefaultDetector_DiamondPatternWithCycle(t *testing.T) {
FILE: detector/detector.go
type Detector (line 20) | type Detector interface
FILE: effector/default_effector.go
type DefaultEffector (line 24) | type DefaultEffector struct
method MergeEffects (line 34) | func (e *DefaultEffector) MergeEffects(expr string, effects []Effect, ...
function NewDefaultEffector (line 28) | func NewDefaultEffector() *DefaultEffector {
FILE: effector/effector.go
type Effect (line 18) | type Effect
constant Allow (line 22) | Allow Effect = iota
constant Indeterminate (line 23) | Indeterminate
constant Deny (line 24) | Deny
type Effector (line 28) | type Effector interface
FILE: enforcer.go
type Enforcer (line 38) | type Enforcer struct
method InitWithFile (line 141) | func (e *Enforcer) InitWithFile(modelPath string, policyPath string) e...
method InitWithAdapter (line 147) | func (e *Enforcer) InitWithAdapter(modelPath string, adapter persist.A...
method InitWithModelAndAdapter (line 163) | func (e *Enforcer) InitWithModelAndAdapter(m model.Model, adapter pers...
method initialize (line 184) | func (e *Enforcer) initialize() {
method LoadModel (line 206) | func (e *Enforcer) LoadModel() error {
method GetModel (line 222) | func (e *Enforcer) GetModel() model.Model {
method SetModel (line 227) | func (e *Enforcer) SetModel(m model.Model) {
method GetAdapter (line 235) | func (e *Enforcer) GetAdapter() persist.Adapter {
method SetAdapter (line 240) | func (e *Enforcer) SetAdapter(adapter persist.Adapter) {
method SetWatcher (line 245) | func (e *Enforcer) SetWatcher(watcher persist.Watcher) error {
method GetRoleManager (line 257) | func (e *Enforcer) GetRoleManager() rbac.RoleManager {
method GetNamedRoleManager (line 268) | func (e *Enforcer) GetNamedRoleManager(ptype string) rbac.RoleManager {
method SetRoleManager (line 279) | func (e *Enforcer) SetRoleManager(rm rbac.RoleManager) {
method SetNamedRoleManager (line 285) | func (e *Enforcer) SetNamedRoleManager(ptype string, rm rbac.RoleManag...
method SetEffector (line 291) | func (e *Enforcer) SetEffector(eft effector.Effector) {
method SetLogger (line 296) | func (e *Enforcer) SetLogger(logger log.Logger) {
method SetDetector (line 301) | func (e *Enforcer) SetDetector(d detector.Detector) {
method SetDetectors (line 306) | func (e *Enforcer) SetDetectors(detectors []detector.Detector) {
method RunDetections (line 313) | func (e *Enforcer) RunDetections() error {
method ClearPolicy (line 352) | func (e *Enforcer) ClearPolicy() {
method LoadPolicy (line 363) | func (e *Enforcer) LoadPolicy() error {
method loadPolicyFromAdapter (line 388) | func (e *Enforcer) loadPolicyFromAdapter(baseModel model.Model) (model...
method applyModifiedModel (line 407) | func (e *Enforcer) applyModifiedModel(newModel model.Model) error {
method rebuildRoleLinks (line 435) | func (e *Enforcer) rebuildRoleLinks(newModel model.Model) error {
method rebuildConditionalRoleLinks (line 453) | func (e *Enforcer) rebuildConditionalRoleLinks(newModel model.Model) e...
method loadFilteredPolicy (line 470) | func (e *Enforcer) loadFilteredPolicy(filter interface{}) error {
method LoadFilteredPolicy (line 506) | func (e *Enforcer) LoadFilteredPolicy(filter interface{}) error {
method LoadIncrementalFilteredPolicy (line 513) | func (e *Enforcer) LoadIncrementalFilteredPolicy(filter interface{}) e...
method IsFiltered (line 518) | func (e *Enforcer) IsFiltered() bool {
method SavePolicy (line 527) | func (e *Enforcer) SavePolicy() error {
method getDomainTokens (line 556) | func (e *Enforcer) getDomainTokens() (rDomainToken, pDomainToken strin...
method registerDomainMatchingFunc (line 567) | func (e *Enforcer) registerDomainMatchingFunc(ptype string) {
method initRmMap (line 583) | func (e *Enforcer) initRmMap() {
method EnableEnforce (line 611) | func (e *Enforcer) EnableEnforce(enable bool) {
method EnableAutoNotifyWatcher (line 616) | func (e *Enforcer) EnableAutoNotifyWatcher(enable bool) {
method EnableAutoNotifyDispatcher (line 621) | func (e *Enforcer) EnableAutoNotifyDispatcher(enable bool) {
method EnableAutoSave (line 626) | func (e *Enforcer) EnableAutoSave(autoSave bool) {
method EnableAutoBuildRoleLinks (line 631) | func (e *Enforcer) EnableAutoBuildRoleLinks(autoBuildRoleLinks bool) {
method EnableAcceptJsonRequest (line 636) | func (e *Enforcer) EnableAcceptJsonRequest(acceptJsonRequest bool) {
method BuildRoleLinks (line 641) | func (e *Enforcer) BuildRoleLinks() error {
method BuildIncrementalRoleLinks (line 657) | func (e *Enforcer) BuildIncrementalRoleLinks(op model.PolicyOp, ptype ...
method BuildIncrementalConditionalRoleLinks (line 663) | func (e *Enforcer) BuildIncrementalConditionalRoleLinks(op model.Polic...
method invalidateMatcherMap (line 678) | func (e *Enforcer) invalidateMatcherMap() {
method enforce (line 683) | func (e *Enforcer) enforce(matcher string, explains *[]string, rvals ....
method getAndStoreMatcherExpression (line 909) | func (e *Enforcer) getAndStoreMatcherExpression(hasEval bool, expStrin...
method Enforce (line 927) | func (e *Enforcer) Enforce(rvals ...interface{}) (bool, error) {
method EnforceWithMatcher (line 932) | func (e *Enforcer) EnforceWithMatcher(matcher string, rvals ...interfa...
method EnforceEx (line 937) | func (e *Enforcer) EnforceEx(rvals ...interface{}) (bool, []string, er...
method EnforceExWithMatcher (line 944) | func (e *Enforcer) EnforceExWithMatcher(matcher string, rvals ...inter...
method BatchEnforce (line 951) | func (e *Enforcer) BatchEnforce(requests [][]interface{}) ([]bool, err...
method BatchEnforceWithMatcher (line 964) | func (e *Enforcer) BatchEnforceWithMatcher(matcher string, requests []...
method AddNamedMatchingFunc (line 977) | func (e *Enforcer) AddNamedMatchingFunc(ptype, name string, fn rbac.Ma...
method AddNamedDomainMatchingFunc (line 986) | func (e *Enforcer) AddNamedDomainMatchingFunc(ptype, name string, fn r...
method AddNamedLinkConditionFunc (line 1000) | func (e *Enforcer) AddNamedLinkConditionFunc(ptype, user, role string,...
method AddNamedDomainLinkConditionFunc (line 1010) | func (e *Enforcer) AddNamedDomainLinkConditionFunc(ptype, user, role s...
method SetNamedLinkConditionFuncParams (line 1019) | func (e *Enforcer) SetNamedLinkConditionFuncParams(ptype, user, role s...
method SetNamedDomainLinkConditionFuncParams (line 1029) | func (e *Enforcer) SetNamedDomainLinkConditionFuncParams(ptype, user, ...
type EnforceContext (line 64) | type EnforceContext struct
method GetCacheKey (line 71) | func (e EnforceContext) GetCacheKey() string {
function NewEnforcer (line 85) | func NewEnforcer(params ...interface{}) (*Enforcer, error) {
function NewEnforceContext (line 669) | func NewEnforceContext(suffix string) EnforceContext {
type enforceParameters (line 1038) | type enforceParameters struct
method Get (line 1047) | func (p enforceParameters) Get(name string) (interface{}, error) {
function generateEvalFunction (line 1070) | func generateEvalFunction(functions map[string]govaluate.ExpressionFunct...
FILE: enforcer_backslash_test.go
function TestBackslashHandlingConsistency (line 28) | func TestBackslashHandlingConsistency(t *testing.T) {
FILE: enforcer_cached.go
type CachedEnforcer (line 27) | type CachedEnforcer struct
method EnableCache (line 55) | func (e *CachedEnforcer) EnableCache(enableCache bool) {
method Enforce (line 65) | func (e *CachedEnforcer) Enforce(rvals ...interface{}) (bool, error) {
method LoadPolicy (line 90) | func (e *CachedEnforcer) LoadPolicy() error {
method RemovePolicy (line 99) | func (e *CachedEnforcer) RemovePolicy(params ...interface{}) (bool, er...
method RemovePolicies (line 111) | func (e *CachedEnforcer) RemovePolicies(rules [][]string) (bool, error) {
method getCachedResult (line 129) | func (e *CachedEnforcer) getCachedResult(key string) (res bool, err er...
method SetExpireTime (line 135) | func (e *CachedEnforcer) SetExpireTime(expireTime time.Duration) {
method SetCache (line 139) | func (e *CachedEnforcer) SetCache(c cache.Cache) {
method setCachedResult (line 143) | func (e *CachedEnforcer) setCachedResult(key string, res bool, extra ....
method getKey (line 149) | func (e *CachedEnforcer) getKey(params ...interface{}) (string, bool) {
method InvalidateCache (line 154) | func (e *CachedEnforcer) InvalidateCache() error {
method ClearPolicy (line 177) | func (e *CachedEnforcer) ClearPolicy() {
type CacheableParam (line 35) | type CacheableParam interface
function NewCachedEnforcer (line 40) | func NewCachedEnforcer(params ...interface{}) (*CachedEnforcer, error) {
function GetCacheKey (line 160) | func GetCacheKey(params ...interface{}) (string, bool) {
FILE: enforcer_cached_b_test.go
function BenchmarkCachedRaw (line 22) | func BenchmarkCachedRaw(b *testing.B) {
function BenchmarkCachedBasicModel (line 28) | func BenchmarkCachedBasicModel(b *testing.B) {
function BenchmarkCachedRBACModel (line 37) | func BenchmarkCachedRBACModel(b *testing.B) {
function BenchmarkCachedRBACModelSmall (line 46) | func BenchmarkCachedRBACModelSmall(b *testing.B) {
function BenchmarkCachedRBACModelMedium (line 69) | func BenchmarkCachedRBACModelMedium(b *testing.B) {
function BenchmarkCachedRBACModelLarge (line 99) | func BenchmarkCachedRBACModelLarge(b *testing.B) {
function BenchmarkCachedRBACModelWithResourceRoles (line 128) | func BenchmarkCachedRBACModelWithResourceRoles(b *testing.B) {
function BenchmarkCachedRBACModelWithDomains (line 137) | func BenchmarkCachedRBACModelWithDomains(b *testing.B) {
function BenchmarkCachedABACModel (line 146) | func BenchmarkCachedABACModel(b *testing.B) {
function BenchmarkCachedKeyMatchModel (line 156) | func BenchmarkCachedKeyMatchModel(b *testing.B) {
function BenchmarkCachedRBACModelWithDeny (line 165) | func BenchmarkCachedRBACModelWithDeny(b *testing.B) {
function BenchmarkCachedPriorityModel (line 174) | func BenchmarkCachedPriorityModel(b *testing.B) {
function BenchmarkCachedWithEnforceContext (line 183) | func BenchmarkCachedWithEnforceContext(b *testing.B) {
function BenchmarkCachedRBACModelMediumParallel (line 192) | func BenchmarkCachedRBACModelMediumParallel(b *testing.B) {
FILE: enforcer_cached_gfunction_test.go
function TestCachedGFunctionAfterAddingGroupingPolicy (line 23) | func TestCachedGFunctionAfterAddingGroupingPolicy(t *testing.T) {
function TestCachedGFunctionWithMultipleEnforceCalls (line 68) | func TestCachedGFunctionWithMultipleEnforceCalls(t *testing.T) {
function TestCachedGFunctionAfterRemovingGroupingPolicy (line 114) | func TestCachedGFunctionAfterRemovingGroupingPolicy(t *testing.T) {
function TestCachedGFunctionAfterBuildRoleLinks (line 156) | func TestCachedGFunctionAfterBuildRoleLinks(t *testing.T) {
FILE: enforcer_cached_synced.go
type SyncedCachedEnforcer (line 26) | type SyncedCachedEnforcer struct
method EnableCache (line 50) | func (e *SyncedCachedEnforcer) EnableCache(enableCache bool) {
method Enforce (line 60) | func (e *SyncedCachedEnforcer) Enforce(rvals ...interface{}) (bool, er...
method LoadPolicy (line 85) | func (e *SyncedCachedEnforcer) LoadPolicy() error {
method AddPolicy (line 94) | func (e *SyncedCachedEnforcer) AddPolicy(params ...interface{}) (bool,...
method AddPolicies (line 101) | func (e *SyncedCachedEnforcer) AddPolicies(rules [][]string) (bool, er...
method RemovePolicy (line 108) | func (e *SyncedCachedEnforcer) RemovePolicy(params ...interface{}) (bo...
method RemovePolicies (line 115) | func (e *SyncedCachedEnforcer) RemovePolicies(rules [][]string) (bool,...
method getCachedResult (line 122) | func (e *SyncedCachedEnforcer) getCachedResult(key string) (res bool, ...
method SetExpireTime (line 126) | func (e *SyncedCachedEnforcer) SetExpireTime(expireTime time.Duration) {
method SetCache (line 133) | func (e *SyncedCachedEnforcer) SetCache(c cache.Cache) {
method setCachedResult (line 139) | func (e *SyncedCachedEnforcer) setCachedResult(key string, res bool, e...
method getKey (line 143) | func (e *SyncedCachedEnforcer) getKey(params ...interface{}) (string, ...
method InvalidateCache (line 148) | func (e *SyncedCachedEnforcer) InvalidateCache() error {
method checkOneAndRemoveCache (line 152) | func (e *SyncedCachedEnforcer) checkOneAndRemoveCache(params ...interf...
method checkManyAndRemoveCache (line 164) | func (e *SyncedCachedEnforcer) checkManyAndRemoveCache(rules [][]strin...
function NewSyncedCachedEnforcer (line 35) | func NewSyncedCachedEnforcer(params ...interface{}) (*SyncedCachedEnforc...
FILE: enforcer_cached_synced_test.go
function testSyncEnforceCache (line 23) | func testSyncEnforceCache(t *testing.T, e *SyncedCachedEnforcer, sub str...
function TestSyncCache (line 30) | func TestSyncCache(t *testing.T) {
FILE: enforcer_cached_test.go
function testEnforceCache (line 19) | func testEnforceCache(t *testing.T, e *CachedEnforcer, sub string, obj i...
function TestCache (line 26) | func TestCache(t *testing.T) {
FILE: enforcer_context.go
type ContextEnforcer (line 28) | type ContextEnforcer struct
method LoadPolicyCtx (line 56) | func (e *ContextEnforcer) LoadPolicyCtx(ctx context.Context) error {
method loadPolicyFromAdapterCtx (line 68) | func (e *ContextEnforcer) loadPolicyFromAdapterCtx(ctx context.Context...
method IsFilteredCtx (line 134) | func (e *ContextEnforcer) IsFilteredCtx(ctx context.Context) bool {
method SavePolicyCtx (line 142) | func (e *ContextEnforcer) SavePolicyCtx(ctx context.Context) error {
method AddPolicyCtx (line 162) | func (e *ContextEnforcer) AddPolicyCtx(ctx context.Context, params ......
method AddPoliciesCtx (line 167) | func (e *ContextEnforcer) AddPoliciesCtx(ctx context.Context, rules []...
method AddNamedPolicyCtx (line 172) | func (e *ContextEnforcer) AddNamedPolicyCtx(ctx context.Context, ptype...
method AddNamedPoliciesCtx (line 186) | func (e *ContextEnforcer) AddNamedPoliciesCtx(ctx context.Context, pty...
method AddPoliciesExCtx (line 190) | func (e *ContextEnforcer) AddPoliciesExCtx(ctx context.Context, rules ...
method AddNamedPoliciesExCtx (line 194) | func (e *ContextEnforcer) AddNamedPoliciesExCtx(ctx context.Context, p...
method RemovePolicyCtx (line 199) | func (e *ContextEnforcer) RemovePolicyCtx(ctx context.Context, params ...
method RemoveNamedPolicyCtx (line 204) | func (e *ContextEnforcer) RemoveNamedPolicyCtx(ctx context.Context, pt...
method RemovePoliciesCtx (line 217) | func (e *ContextEnforcer) RemovePoliciesCtx(ctx context.Context, rules...
method RemoveNamedPoliciesCtx (line 222) | func (e *ContextEnforcer) RemoveNamedPoliciesCtx(ctx context.Context, ...
method RemoveFilteredPolicyCtx (line 227) | func (e *ContextEnforcer) RemoveFilteredPolicyCtx(ctx context.Context,...
method RemoveFilteredNamedPolicyCtx (line 232) | func (e *ContextEnforcer) RemoveFilteredNamedPolicyCtx(ctx context.Con...
method UpdatePolicyCtx (line 237) | func (e *ContextEnforcer) UpdatePolicyCtx(ctx context.Context, oldPoli...
method UpdateNamedPolicyCtx (line 242) | func (e *ContextEnforcer) UpdateNamedPolicyCtx(ctx context.Context, pt...
method UpdatePoliciesCtx (line 247) | func (e *ContextEnforcer) UpdatePoliciesCtx(ctx context.Context, oldPo...
method UpdateNamedPoliciesCtx (line 252) | func (e *ContextEnforcer) UpdateNamedPoliciesCtx(ctx context.Context, ...
method UpdateFilteredPoliciesCtx (line 257) | func (e *ContextEnforcer) UpdateFilteredPoliciesCtx(ctx context.Contex...
method UpdateFilteredNamedPoliciesCtx (line 262) | func (e *ContextEnforcer) UpdateFilteredNamedPoliciesCtx(ctx context.C...
method AddGroupingPolicyCtx (line 269) | func (e *ContextEnforcer) AddGroupingPolicyCtx(ctx context.Context, pa...
method AddGroupingPoliciesCtx (line 274) | func (e *ContextEnforcer) AddGroupingPoliciesCtx(ctx context.Context, ...
method AddGroupingPoliciesExCtx (line 278) | func (e *ContextEnforcer) AddGroupingPoliciesExCtx(ctx context.Context...
method AddNamedGroupingPolicyCtx (line 283) | func (e *ContextEnforcer) AddNamedGroupingPolicyCtx(ctx context.Contex...
method AddNamedGroupingPoliciesCtx (line 300) | func (e *ContextEnforcer) AddNamedGroupingPoliciesCtx(ctx context.Cont...
method AddNamedGroupingPoliciesExCtx (line 304) | func (e *ContextEnforcer) AddNamedGroupingPoliciesExCtx(ctx context.Co...
method RemoveGroupingPolicyCtx (line 309) | func (e *ContextEnforcer) RemoveGroupingPolicyCtx(ctx context.Context,...
method RemoveNamedGroupingPolicyCtx (line 314) | func (e *ContextEnforcer) RemoveNamedGroupingPolicyCtx(ctx context.Con...
method RemoveGroupingPoliciesCtx (line 332) | func (e *ContextEnforcer) RemoveGroupingPoliciesCtx(ctx context.Contex...
method RemoveNamedGroupingPoliciesCtx (line 337) | func (e *ContextEnforcer) RemoveNamedGroupingPoliciesCtx(ctx context.C...
method RemoveFilteredGroupingPolicyCtx (line 342) | func (e *ContextEnforcer) RemoveFilteredGroupingPolicyCtx(ctx context....
method RemoveFilteredNamedGroupingPolicyCtx (line 347) | func (e *ContextEnforcer) RemoveFilteredNamedGroupingPolicyCtx(ctx con...
method UpdateGroupingPolicyCtx (line 352) | func (e *ContextEnforcer) UpdateGroupingPolicyCtx(ctx context.Context,...
method UpdateNamedGroupingPolicyCtx (line 357) | func (e *ContextEnforcer) UpdateNamedGroupingPolicyCtx(ctx context.Con...
method UpdateGroupingPoliciesCtx (line 362) | func (e *ContextEnforcer) UpdateGroupingPoliciesCtx(ctx context.Contex...
method UpdateNamedGroupingPoliciesCtx (line 367) | func (e *ContextEnforcer) UpdateNamedGroupingPoliciesCtx(ctx context.C...
method SelfAddPolicyCtx (line 374) | func (e *ContextEnforcer) SelfAddPolicyCtx(ctx context.Context, sec st...
method SelfAddPoliciesCtx (line 379) | func (e *ContextEnforcer) SelfAddPoliciesCtx(ctx context.Context, sec ...
method SelfAddPoliciesExCtx (line 383) | func (e *ContextEnforcer) SelfAddPoliciesExCtx(ctx context.Context, se...
method SelfRemovePolicyCtx (line 388) | func (e *ContextEnforcer) SelfRemovePolicyCtx(ctx context.Context, sec...
method SelfRemovePoliciesCtx (line 393) | func (e *ContextEnforcer) SelfRemovePoliciesCtx(ctx context.Context, s...
method SelfRemoveFilteredPolicyCtx (line 398) | func (e *ContextEnforcer) SelfRemoveFilteredPolicyCtx(ctx context.Cont...
method SelfUpdatePolicyCtx (line 403) | func (e *ContextEnforcer) SelfUpdatePolicyCtx(ctx context.Context, sec...
method SelfUpdatePoliciesCtx (line 408) | func (e *ContextEnforcer) SelfUpdatePoliciesCtx(ctx context.Context, s...
method addPolicyWithoutNotifyCtx (line 415) | func (e *ContextEnforcer) addPolicyWithoutNotifyCtx(ctx context.Contex...
method addPoliciesWithoutNotifyCtx (line 449) | func (e *ContextEnforcer) addPoliciesWithoutNotifyCtx(ctx context.Cont...
method removePolicyWithoutNotifyCtx (line 490) | func (e *ContextEnforcer) removePolicyWithoutNotifyCtx(ctx context.Con...
method removePoliciesWithoutNotifyCtx (line 519) | func (e *ContextEnforcer) removePoliciesWithoutNotifyCtx(ctx context.C...
method removeFilteredPolicyWithoutNotifyCtx (line 551) | func (e *ContextEnforcer) removeFilteredPolicyWithoutNotifyCtx(ctx con...
method updatePolicyWithoutNotifyCtx (line 584) | func (e *ContextEnforcer) updatePolicyWithoutNotifyCtx(ctx context.Con...
method updatePoliciesWithoutNotifyCtx (line 615) | func (e *ContextEnforcer) updatePoliciesWithoutNotifyCtx(ctx context.C...
method addPolicyCtx (line 651) | func (e *ContextEnforcer) addPolicyCtx(ctx context.Context, sec string...
method addPoliciesCtx (line 670) | func (e *ContextEnforcer) addPoliciesCtx(ctx context.Context, sec stri...
method updatePolicyCtx (line 689) | func (e *ContextEnforcer) updatePolicyCtx(ctx context.Context, sec str...
method updatePoliciesCtx (line 708) | func (e *ContextEnforcer) updatePoliciesCtx(ctx context.Context, sec s...
method removePolicyCtx (line 727) | func (e *ContextEnforcer) removePolicyCtx(ctx context.Context, sec str...
method removePoliciesCtx (line 746) | func (e *ContextEnforcer) removePoliciesCtx(ctx context.Context, sec s...
method removeFilteredPolicyCtx (line 766) | func (e *ContextEnforcer) removeFilteredPolicyCtx(ctx context.Context,...
method updateFilteredPoliciesCtx (line 785) | func (e *ContextEnforcer) updateFilteredPoliciesCtx(ctx context.Contex...
method updateFilteredPoliciesWithoutNotifyCtx (line 805) | func (e *ContextEnforcer) updateFilteredPoliciesWithoutNotifyCtx(ctx c...
function NewContextEnforcer (line 34) | func NewContextEnforcer(params ...interface{}) (IEnforcerContext, error) {
method LoadFilteredPolicyCtx (line 88) | func (e *Enforcer) LoadFilteredPolicyCtx(ctx context.Context, filter int...
method LoadIncrementalFilteredPolicyCtx (line 94) | func (e *Enforcer) LoadIncrementalFilteredPolicyCtx(ctx context.Context,...
method loadFilteredPolicyCtx (line 98) | func (e *Enforcer) loadFilteredPolicyCtx(ctx context.Context, filter int...
FILE: enforcer_context_interface.go
type IEnforcerContext (line 19) | type IEnforcerContext interface
FILE: enforcer_context_test.go
function TestIEnforcerContext_BasicOperations (line 23) | func TestIEnforcerContext_BasicOperations(t *testing.T) {
function TestIEnforcerContext_RBACOperations (line 58) | func TestIEnforcerContext_RBACOperations(t *testing.T) {
function TestIEnforcerContext_BatchOperations (line 99) | func TestIEnforcerContext_BatchOperations(t *testing.T) {
function TestIEnforcerContext_ContextCancellation (line 128) | func TestIEnforcerContext_ContextCancellation(t *testing.T) {
function TestIEnforcerContext_ContextTimeout (line 143) | func TestIEnforcerContext_ContextTimeout(t *testing.T) {
function TestIEnforcerContext_GroupingPolicyOperations (line 160) | func TestIEnforcerContext_GroupingPolicyOperations(t *testing.T) {
function TestIEnforcerContext_UpdateOperations (line 185) | func TestIEnforcerContext_UpdateOperations(t *testing.T) {
function TestIEnforcerContext_SelfMethods (line 209) | func TestIEnforcerContext_SelfMethods(t *testing.T) {
FILE: enforcer_distributed.go
type DistributedEnforcer (line 9) | type DistributedEnforcer struct
method SetDispatcher (line 25) | func (d *DistributedEnforcer) SetDispatcher(dispatcher persist.Dispatc...
method AddPoliciesSelf (line 31) | func (d *DistributedEnforcer) AddPoliciesSelf(shouldPersist func() boo...
method RemovePoliciesSelf (line 69) | func (d *DistributedEnforcer) RemovePoliciesSelf(shouldPersist func() ...
method RemoveFilteredPolicySelf (line 97) | func (d *DistributedEnforcer) RemoveFilteredPolicySelf(shouldPersist f...
method ClearPolicySelf (line 124) | func (d *DistributedEnforcer) ClearPolicySelf(shouldPersist func() boo...
method UpdatePolicySelf (line 140) | func (d *DistributedEnforcer) UpdatePolicySelf(shouldPersist func() bo...
method UpdatePoliciesSelf (line 170) | func (d *DistributedEnforcer) UpdatePoliciesSelf(shouldPersist func() ...
method UpdateFilteredPoliciesSelf (line 200) | func (d *DistributedEnforcer) UpdateFilteredPoliciesSelf(shouldPersist...
function NewDistributedEnforcer (line 13) | func NewDistributedEnforcer(params ...interface{}) (*DistributedEnforcer...
FILE: enforcer_interface.go
type IEnforcer (line 30) | type IEnforcer interface
type IDistributedEnforcer (line 168) | type IDistributedEnforcer interface
FILE: enforcer_json_test.go
function TestInvalidJsonRequest (line 10) | func TestInvalidJsonRequest(t *testing.T) {
FILE: enforcer_synced.go
type SyncedEnforcer (line 29) | type SyncedEnforcer struct
method GetLock (line 51) | func (e *SyncedEnforcer) GetLock() *sync.RWMutex {
method GetRoleManager (line 56) | func (e *SyncedEnforcer) GetRoleManager() rbac.RoleManager {
method GetNamedRoleManager (line 63) | func (e *SyncedEnforcer) GetNamedRoleManager(ptype string) rbac.RoleMa...
method SetRoleManager (line 70) | func (e *SyncedEnforcer) SetRoleManager(rm rbac.RoleManager) {
method SetNamedRoleManager (line 77) | func (e *SyncedEnforcer) SetNamedRoleManager(ptype string, rm rbac.Rol...
method IsAutoLoadingRunning (line 84) | func (e *SyncedEnforcer) IsAutoLoadingRunning() bool {
method StartAutoLoadPolicy (line 89) | func (e *SyncedEnforcer) StartAutoLoadPolicy(d time.Duration) {
method StopAutoLoadPolicy (line 118) | func (e *SyncedEnforcer) StopAutoLoadPolicy() {
method SetWatcher (line 125) | func (e *SyncedEnforcer) SetWatcher(watcher persist.Watcher) error {
method LoadModel (line 132) | func (e *SyncedEnforcer) LoadModel() error {
method ClearPolicy (line 139) | func (e *SyncedEnforcer) ClearPolicy() {
method LoadPolicy (line 146) | func (e *SyncedEnforcer) LoadPolicy() error {
method LoadFilteredPolicy (line 163) | func (e *SyncedEnforcer) LoadFilteredPolicy(filter interface{}) error {
method LoadIncrementalFilteredPolicy (line 170) | func (e *SyncedEnforcer) LoadIncrementalFilteredPolicy(filter interfac...
method SavePolicy (line 177) | func (e *SyncedEnforcer) SavePolicy() error {
method BuildRoleLinks (line 184) | func (e *SyncedEnforcer) BuildRoleLinks() error {
method Enforce (line 191) | func (e *SyncedEnforcer) Enforce(rvals ...interface{}) (bool, error) {
method EnforceWithMatcher (line 198) | func (e *SyncedEnforcer) EnforceWithMatcher(matcher string, rvals ...i...
method EnforceEx (line 205) | func (e *SyncedEnforcer) EnforceEx(rvals ...interface{}) (bool, []stri...
method EnforceExWithMatcher (line 212) | func (e *SyncedEnforcer) EnforceExWithMatcher(matcher string, rvals .....
method BatchEnforce (line 219) | func (e *SyncedEnforcer) BatchEnforce(requests [][]interface{}) ([]boo...
method BatchEnforceWithMatcher (line 226) | func (e *SyncedEnforcer) BatchEnforceWithMatcher(matcher string, reque...
method GetAllSubjects (line 233) | func (e *SyncedEnforcer) GetAllSubjects() ([]string, error) {
method GetAllNamedSubjects (line 240) | func (e *SyncedEnforcer) GetAllNamedSubjects(ptype string) ([]string, ...
method GetAllObjects (line 247) | func (e *SyncedEnforcer) GetAllObjects() ([]string, error) {
method GetAllNamedObjects (line 254) | func (e *SyncedEnforcer) GetAllNamedObjects(ptype string) ([]string, e...
method GetAllActions (line 261) | func (e *SyncedEnforcer) GetAllActions() ([]string, error) {
method GetAllNamedActions (line 268) | func (e *SyncedEnforcer) GetAllNamedActions(ptype string) ([]string, e...
method GetAllRoles (line 275) | func (e *SyncedEnforcer) GetAllRoles() ([]string, error) {
method GetAllNamedRoles (line 282) | func (e *SyncedEnforcer) GetAllNamedRoles(ptype string) ([]string, err...
method GetAllUsers (line 289) | func (e *SyncedEnforcer) GetAllUsers() ([]string, error) {
method GetPolicy (line 296) | func (e *SyncedEnforcer) GetPolicy() ([][]string, error) {
method GetFilteredPolicy (line 303) | func (e *SyncedEnforcer) GetFilteredPolicy(fieldIndex int, fieldValues...
method GetNamedPolicy (line 310) | func (e *SyncedEnforcer) GetNamedPolicy(ptype string) ([][]string, err...
method GetFilteredNamedPolicy (line 317) | func (e *SyncedEnforcer) GetFilteredNamedPolicy(ptype string, fieldInd...
method GetGroupingPolicy (line 324) | func (e *SyncedEnforcer) GetGroupingPolicy() ([][]string, error) {
method GetFilteredGroupingPolicy (line 331) | func (e *SyncedEnforcer) GetFilteredGroupingPolicy(fieldIndex int, fie...
method GetNamedGroupingPolicy (line 338) | func (e *SyncedEnforcer) GetNamedGroupingPolicy(ptype string) ([][]str...
method GetFilteredNamedGroupingPolicy (line 345) | func (e *SyncedEnforcer) GetFilteredNamedGroupingPolicy(ptype string, ...
method HasPolicy (line 352) | func (e *SyncedEnforcer) HasPolicy(params ...interface{}) (bool, error) {
method HasNamedPolicy (line 359) | func (e *SyncedEnforcer) HasNamedPolicy(ptype string, params ...interf...
method AddPolicy (line 368) | func (e *SyncedEnforcer) AddPolicy(params ...interface{}) (bool, error) {
method AddPolicies (line 377) | func (e *SyncedEnforcer) AddPolicies(rules [][]string) (bool, error) {
method AddPoliciesEx (line 386) | func (e *SyncedEnforcer) AddPoliciesEx(rules [][]string) (bool, error) {
method AddNamedPolicy (line 395) | func (e *SyncedEnforcer) AddNamedPolicy(ptype string, params ...interf...
method AddNamedPolicies (line 404) | func (e *SyncedEnforcer) AddNamedPolicies(ptype string, rules [][]stri...
method AddNamedPoliciesEx (line 413) | func (e *SyncedEnforcer) AddNamedPoliciesEx(ptype string, rules [][]st...
method RemovePolicy (line 420) | func (e *SyncedEnforcer) RemovePolicy(params ...interface{}) (bool, er...
method UpdatePolicy (line 427) | func (e *SyncedEnforcer) UpdatePolicy(oldPolicy []string, newPolicy []...
method UpdateNamedPolicy (line 433) | func (e *SyncedEnforcer) UpdateNamedPolicy(ptype string, p1 []string, ...
method UpdatePolicies (line 440) | func (e *SyncedEnforcer) UpdatePolicies(oldPolices [][]string, newPoli...
method UpdateNamedPolicies (line 446) | func (e *SyncedEnforcer) UpdateNamedPolicies(ptype string, p1 [][]stri...
method UpdateFilteredPolicies (line 452) | func (e *SyncedEnforcer) UpdateFilteredPolicies(newPolicies [][]string...
method UpdateFilteredNamedPolicies (line 458) | func (e *SyncedEnforcer) UpdateFilteredNamedPolicies(ptype string, new...
method RemovePolicies (line 465) | func (e *SyncedEnforcer) RemovePolicies(rules [][]string) (bool, error) {
method RemoveFilteredPolicy (line 472) | func (e *SyncedEnforcer) RemoveFilteredPolicy(fieldIndex int, fieldVal...
method RemoveNamedPolicy (line 479) | func (e *SyncedEnforcer) RemoveNamedPolicy(ptype string, params ...int...
method RemoveNamedPolicies (line 486) | func (e *SyncedEnforcer) RemoveNamedPolicies(ptype string, rules [][]s...
method RemoveFilteredNamedPolicy (line 493) | func (e *SyncedEnforcer) RemoveFilteredNamedPolicy(ptype string, field...
method HasGroupingPolicy (line 500) | func (e *SyncedEnforcer) HasGroupingPolicy(params ...interface{}) (boo...
method HasNamedGroupingPolicy (line 507) | func (e *SyncedEnforcer) HasNamedGroupingPolicy(ptype string, params ....
method AddGroupingPolicy (line 516) | func (e *SyncedEnforcer) AddGroupingPolicy(params ...interface{}) (boo...
method AddGroupingPolicies (line 525) | func (e *SyncedEnforcer) AddGroupingPolicies(rules [][]string) (bool, ...
method AddGroupingPoliciesEx (line 534) | func (e *SyncedEnforcer) AddGroupingPoliciesEx(rules [][]string) (bool...
method AddNamedGroupingPolicy (line 543) | func (e *SyncedEnforcer) AddNamedGroupingPolicy(ptype string, params ....
method AddNamedGroupingPolicies (line 552) | func (e *SyncedEnforcer) AddNamedGroupingPolicies(ptype string, rules ...
method AddNamedGroupingPoliciesEx (line 561) | func (e *SyncedEnforcer) AddNamedGroupingPoliciesEx(ptype string, rule...
method RemoveGroupingPolicy (line 568) | func (e *SyncedEnforcer) RemoveGroupingPolicy(params ...interface{}) (...
method RemoveGroupingPolicies (line 575) | func (e *SyncedEnforcer) RemoveGroupingPolicies(rules [][]string) (boo...
method RemoveFilteredGroupingPolicy (line 582) | func (e *SyncedEnforcer) RemoveFilteredGroupingPolicy(fieldIndex int, ...
method RemoveNamedGroupingPolicy (line 589) | func (e *SyncedEnforcer) RemoveNamedGroupingPolicy(ptype string, param...
method RemoveNamedGroupingPolicies (line 596) | func (e *SyncedEnforcer) RemoveNamedGroupingPolicies(ptype string, rul...
method UpdateGroupingPolicy (line 602) | func (e *SyncedEnforcer) UpdateGroupingPolicy(oldRule []string, newRul...
method UpdateGroupingPolicies (line 608) | func (e *SyncedEnforcer) UpdateGroupingPolicies(oldRules [][]string, n...
method UpdateNamedGroupingPolicy (line 614) | func (e *SyncedEnforcer) UpdateNamedGroupingPolicy(ptype string, oldRu...
method UpdateNamedGroupingPolicies (line 620) | func (e *SyncedEnforcer) UpdateNamedGroupingPolicies(ptype string, old...
method RemoveFilteredNamedGroupingPolicy (line 627) | func (e *SyncedEnforcer) RemoveFilteredNamedGroupingPolicy(ptype strin...
method AddFunction (line 634) | func (e *SyncedEnforcer) AddFunction(name string, function govaluate.E...
method SelfAddPolicy (line 640) | func (e *SyncedEnforcer) SelfAddPolicy(sec string, ptype string, rule ...
method SelfAddPolicies (line 646) | func (e *SyncedEnforcer) SelfAddPolicies(sec string, ptype string, rul...
method SelfAddPoliciesEx (line 652) | func (e *SyncedEnforcer) SelfAddPoliciesEx(sec string, ptype string, r...
method SelfRemovePolicy (line 658) | func (e *SyncedEnforcer) SelfRemovePolicy(sec string, ptype string, ru...
method SelfRemovePolicies (line 664) | func (e *SyncedEnforcer) SelfRemovePolicies(sec string, ptype string, ...
method SelfRemoveFilteredPolicy (line 670) | func (e *SyncedEnforcer) SelfRemoveFilteredPolicy(sec string, ptype st...
method SelfUpdatePolicy (line 676) | func (e *SyncedEnforcer) SelfUpdatePolicy(sec string, ptype string, ol...
method SelfUpdatePolicies (line 682) | func (e *SyncedEnforcer) SelfUpdatePolicies(sec string, ptype string, ...
function NewSyncedEnforcer (line 37) | func NewSyncedEnforcer(params ...interface{}) (*SyncedEnforcer, error) {
FILE: enforcer_synced_test.go
function testEnforceSync (line 26) | func testEnforceSync(t *testing.T, e *SyncedEnforcer, sub string, obj in...
function TestSync (line 33) | func TestSync(t *testing.T) {
function TestStopAutoLoadPolicy (line 60) | func TestStopAutoLoadPolicy(t *testing.T) {
function testSyncedEnforcerGetPolicy (line 74) | func testSyncedEnforcerGetPolicy(t *testing.T, e *SyncedEnforcer, res []...
function TestSyncedEnforcerSelfAddPolicy (line 88) | func TestSyncedEnforcerSelfAddPolicy(t *testing.T) {
function TestSyncedEnforcerSelfAddPolicies (line 112) | func TestSyncedEnforcerSelfAddPolicies(t *testing.T) {
function TestSyncedEnforcerSelfAddPoliciesEx (line 140) | func TestSyncedEnforcerSelfAddPoliciesEx(t *testing.T) {
function TestSyncedEnforcerSelfRemovePolicy (line 177) | func TestSyncedEnforcerSelfRemovePolicy(t *testing.T) {
function TestSyncedEnforcerSelfRemovePolicies (line 215) | func TestSyncedEnforcerSelfRemovePolicies(t *testing.T) {
function TestSyncedEnforcerSelfRemoveFilteredPolicy (line 256) | func TestSyncedEnforcerSelfRemoveFilteredPolicy(t *testing.T) {
function TestSyncedEnforcerSelfUpdatePolicy (line 297) | func TestSyncedEnforcerSelfUpdatePolicy(t *testing.T) {
function TestSyncedEnforcerSelfUpdatePolicies (line 352) | func TestSyncedEnforcerSelfUpdatePolicies(t *testing.T) {
function TestSyncedEnforcerAddPoliciesEx (line 406) | func TestSyncedEnforcerAddPoliciesEx(t *testing.T) {
function TestSyncedEnforcerAddNamedPoliciesEx (line 432) | func TestSyncedEnforcerAddNamedPoliciesEx(t *testing.T) {
function testSyncedEnforcerGetUsers (line 474) | func testSyncedEnforcerGetUsers(t *testing.T, e *SyncedEnforcer, res []s...
function TestSyncedEnforcerAddGroupingPoliciesEx (line 495) | func TestSyncedEnforcerAddGroupingPoliciesEx(t *testing.T) {
function TestSyncedEnforcerAddNamedGroupingPoliciesEx (line 515) | func TestSyncedEnforcerAddNamedGroupingPoliciesEx(t *testing.T) {
FILE: enforcer_test.go
function TestKeyMatchModelInMemory (line 28) | func TestKeyMatchModelInMemory(t *testing.T) {
function TestKeyMatchWithRBACInDomain (line 87) | func TestKeyMatchWithRBACInDomain(t *testing.T) {
function TestKeyMatchModelInMemoryDeny (line 92) | func TestKeyMatchModelInMemoryDeny(t *testing.T) {
function TestRBACModelInMemoryIndeterminate (line 106) | func TestRBACModelInMemoryIndeterminate(t *testing.T) {
function TestRBACModelInMemory (line 121) | func TestRBACModelInMemory(t *testing.T) {
function TestRBACModelInMemory2 (line 147) | func TestRBACModelInMemory2(t *testing.T) {
function TestNotUsedRBACModelInMemory (line 188) | func TestNotUsedRBACModelInMemory(t *testing.T) {
function TestMatcherUsingInOperator (line 211) | func TestMatcherUsingInOperator(t *testing.T) {
function TestMatcherUsingInOperatorBracket (line 224) | func TestMatcherUsingInOperatorBracket(t *testing.T) {
function TestReloadPolicy (line 236) | func TestReloadPolicy(t *testing.T) {
function TestSavePolicy (line 243) | func TestSavePolicy(t *testing.T) {
function TestClearPolicy (line 249) | func TestClearPolicy(t *testing.T) {
function TestEnableEnforce (line 255) | func TestEnableEnforce(t *testing.T) {
function TestEnableLog (line 279) | func TestEnableLog(t *testing.T) {
function TestEnableAutoSave (line 294) | func TestEnableAutoSave(t *testing.T) {
function TestInitWithAdapter (line 331) | func TestInitWithAdapter(t *testing.T) {
function TestRoleLinks (line 345) | func TestRoleLinks(t *testing.T) {
function TestEnforceConcurrency (line 352) | func TestEnforceConcurrency(t *testing.T) {
function TestGetAndSetModel (line 376) | func TestGetAndSetModel(t *testing.T) {
function TestGetAndSetAdapterInMem (line 387) | func TestGetAndSetAdapterInMem(t *testing.T) {
function TestSetAdapterFromFile (line 402) | func TestSetAdapterFromFile(t *testing.T) {
function TestInitEmpty (line 414) | func TestInitEmpty(t *testing.T) {
function testEnforceEx (line 431) | func testEnforceEx(t *testing.T, e *Enforcer, sub, obj, act interface{},...
function TestEnforceEx (line 440) | func TestEnforceEx(t *testing.T) {
function TestEnforceExLog (line 478) | func TestEnforceExLog(t *testing.T) {
function testBatchEnforce (line 493) | func testBatchEnforce(t *testing.T, e *Enforcer, requests [][]interface{...
function TestBatchEnforce (line 506) | func TestBatchEnforce(t *testing.T) {
function TestSubjectPriority (line 512) | func TestSubjectPriority(t *testing.T) {
function TestSubjectPriorityWithDomain (line 522) | func TestSubjectPriorityWithDomain(t *testing.T) {
function TestSubjectPriorityInFilter (line 532) | func TestSubjectPriorityInFilter(t *testing.T) {
function TestMultiplePolicyDefinitions (line 551) | func TestMultiplePolicyDefinitions(t *testing.T) {
function TestPriorityExplicit (line 564) | func TestPriorityExplicit(t *testing.T) {
function TestFailedToLoadPolicy (line 598) | func TestFailedToLoadPolicy(t *testing.T) {
function TestReloadPolicyWithFunc (line 609) | func TestReloadPolicyWithFunc(t *testing.T) {
function TestEvalPriority (line 619) | func TestEvalPriority(t *testing.T) {
function TestLinkConditionFunc (line 626) | func TestLinkConditionFunc(t *testing.T) {
function TestEnforcerWithDefaultDetector (line 730) | func TestEnforcerWithDefaultDetector(t *testing.T) {
function TestEnforcerRunDetections (line 745) | func TestEnforcerRunDetections(t *testing.T) {
function TestEnforcerSetDetector (line 772) | func TestEnforcerSetDetector(t *testing.T) {
function TestEnforcerSetDetectors (line 787) | func TestEnforcerSetDetectors(t *testing.T) {
FILE: enforcer_transactional.go
type TransactionalEnforcer (line 30) | type TransactionalEnforcer struct
method BeginTransaction (line 52) | func (te *TransactionalEnforcer) BeginTransaction(ctx context.Context)...
method GetTransaction (line 83) | func (te *TransactionalEnforcer) GetTransaction(id string) *Transaction {
method IsTransactionActive (line 91) | func (te *TransactionalEnforcer) IsTransactionActive(id string) bool {
method WithTransaction (line 101) | func (te *TransactionalEnforcer) WithTransaction(ctx context.Context, ...
function NewTransactionalEnforcer (line 39) | func NewTransactionalEnforcer(params ...interface{}) (*TransactionalEnfo...
FILE: error_test.go
function TestPathError (line 23) | func TestPathError(t *testing.T) {
function TestEnforcerParamError (line 33) | func TestEnforcerParamError(t *testing.T) {
function TestModelError (line 51) | func TestModelError(t *testing.T) {
function TestEnforceError (line 71) | func TestEnforceError(t *testing.T) {
function TestNoError (line 91) | func TestNoError(t *testing.T) {
function TestModelNoError (line 116) | func TestModelNoError(t *testing.T) {
function TestMockAdapterErrors (line 130) | func TestMockAdapterErrors(t *testing.T) {
FILE: errors/constraint_errors.go
type ConstraintViolationError (line 31) | type ConstraintViolationError struct
method Error (line 36) | func (e *ConstraintViolationError) Error() string {
function NewConstraintViolationError (line 41) | func NewConstraintViolationError(constraintName, message string) error {
FILE: filter_test.go
function TestInitFilteredAdapter (line 24) | func TestInitFilteredAdapter(t *testing.T) {
function TestLoadFilteredPolicy (line 34) | func TestLoadFilteredPolicy(t *testing.T) {
function TestLoadMoreTypeFilteredPolicy (line 69) | func TestLoadMoreTypeFilteredPolicy(t *testing.T) {
function TestAppendFilteredPolicy (line 109) | func TestAppendFilteredPolicy(t *testing.T) {
function TestFilteredPolicyInvalidFilter (line 149) | func TestFilteredPolicyInvalidFilter(t *testing.T) {
function TestFilteredPolicyEmptyFilter (line 160) | func TestFilteredPolicyEmptyFilter(t *testing.T) {
function TestUnsupportedFilteredPolicy (line 177) | func TestUnsupportedFilteredPolicy(t *testing.T) {
function TestFilteredAdapterEmptyFilepath (line 189) | func TestFilteredAdapterEmptyFilepath(t *testing.T) {
function TestFilteredAdapterInvalidFilepath (line 200) | func TestFilteredAdapterInvalidFilepath(t *testing.T) {
FILE: frontend.go
function CasbinJsGetPermissionForUser (line 22) | func CasbinJsGetPermissionForUser(e IEnforcer, user string) (string, err...
FILE: frontend_old.go
function CasbinJsGetPermissionForUserOld (line 19) | func CasbinJsGetPermissionForUserOld(e IEnforcer, user string) ([]byte, ...
FILE: frontend_old_test.go
function contains (line 22) | func contains(arr []string, target string) bool {
function TestCasbinJsGetPermissionForUserOld (line 31) | func TestCasbinJsGetPermissionForUserOld(t *testing.T) {
FILE: frontend_test.go
function TestCasbinJsGetPermissionForUser (line 25) | func TestCasbinJsGetPermissionForUser(t *testing.T) {
FILE: internal_api.go
constant notImplemented (line 27) | notImplemented = "not implemented"
method shouldPersist (line 30) | func (e *Enforcer) shouldPersist() bool {
method shouldNotify (line 34) | func (e *Enforcer) shouldNotify() bool {
method validateConstraintsForGroupingPolicy (line 40) | func (e *Enforcer) validateConstraintsForGroupingPolicy() error {
method addPolicyWithoutNotify (line 45) | func (e *Enforcer) addPolicyWithoutNotify(sec string, ptype string, rule...
method addPoliciesWithoutNotify (line 86) | func (e *Enforcer) addPoliciesWithoutNotify(sec string, ptype string, ru...
method removePolicyWithoutNotify (line 132) | func (e *Enforcer) removePolicyWithoutNotify(sec string, ptype string, r...
method updatePolicyWithoutNotify (line 165) | func (e *Enforcer) updatePolicyWithoutNotify(sec string, ptype string, o...
method updatePoliciesWithoutNotify (line 201) | func (e *Enforcer) updatePoliciesWithoutNotify(sec string, ptype string,...
method removePoliciesWithoutNotify (line 243) | func (e *Enforcer) removePoliciesWithoutNotify(sec string, ptype string,...
method removeFilteredPolicyWithoutNotify (line 280) | func (e *Enforcer) removeFilteredPolicyWithoutNotify(sec string, ptype s...
method updateFilteredPoliciesWithoutNotify (line 317) | func (e *Enforcer) updateFilteredPoliciesWithoutNotify(sec string, ptype...
method addPolicy (line 378) | func (e *Enforcer) addPolicy(sec string, ptype string, rule []string) (b...
method addPolicies (line 403) | func (e *Enforcer) addPolicies(sec string, ptype string, rules [][]strin...
method removePolicy (line 423) | func (e *Enforcer) removePolicy(sec string, ptype string, rule []string)...
method updatePolicy (line 445) | func (e *Enforcer) updatePolicy(sec string, ptype string, oldRule []stri...
method updatePolicies (line 464) | func (e *Enforcer) updatePolicies(sec string, ptype string, oldRules [][...
method removePolicies (line 484) | func (e *Enforcer) removePolicies(sec string, ptype string, rules [][]st...
method removeFilteredPolicy (line 504) | func (e *Enforcer) removeFilteredPolicy(sec string, ptype string, fieldI...
method updateFilteredPolicies (line 523) | func (e *Enforcer) updateFilteredPolicies(sec string, ptype string, newR...
method GetFieldIndex (line 543) | func (e *Enforcer) GetFieldIndex(ptype string, field string) (int, error) {
method SetFieldIndex (line 547) | func (e *Enforcer) SetFieldIndex(ptype string, field string, index int) {
FILE: lbac_test.go
function testEnforceLBAC (line 21) | func testEnforceLBAC(t *testing.T, e *Enforcer, sub string, subConf, sub...
function TestLBACModel (line 30) | func TestLBACModel(t *testing.T) {
FILE: log/default_logger.go
type DefaultLogger (line 26) | type DefaultLogger struct
method SetOutput (line 43) | func (l *DefaultLogger) SetOutput(w io.Writer) {
method SetEventTypes (line 51) | func (l *DefaultLogger) SetEventTypes(eventTypes []EventType) error {
method OnBeforeEvent (line 61) | func (l *DefaultLogger) OnBeforeEvent(entry *LogEntry) error {
method OnAfterEvent (line 81) | func (l *DefaultLogger) OnAfterEvent(entry *LogEntry) error {
method SetLogCallback (line 108) | func (l *DefaultLogger) SetLogCallback(callback func(entry *LogEntry) ...
method writeLog (line 114) | func (l *DefaultLogger) writeLog(entry *LogEntry) error {
function NewDefaultLogger (line 34) | func NewDefaultLogger() *DefaultLogger {
FILE: log/logger.go
type Logger (line 18) | type Logger interface
FILE: log/types.go
type EventType (line 20) | type EventType
constant EventEnforce (line 24) | EventEnforce EventType = "enforce"
constant EventAddPolicy (line 25) | EventAddPolicy EventType = "addPolicy"
constant EventRemovePolicy (line 26) | EventRemovePolicy EventType = "removePolicy"
constant EventLoadPolicy (line 27) | EventLoadPolicy EventType = "loadPolicy"
constant EventSavePolicy (line 28) | EventSavePolicy EventType = "savePolicy"
type LogEntry (line 32) | type LogEntry struct
FILE: logger_test.go
function verifyBufferOutput (line 25) | func verifyBufferOutput(t *testing.T, logOutput string) {
function verifyCallbackEntries (line 35) | func verifyCallbackEntries(t *testing.T, entries []*log.LogEntry) {
function TestEnforcerWithDefaultLogger (line 68) | func TestEnforcerWithDefaultLogger(t *testing.T) {
function TestSetEventTypes (line 139) | func TestSetEventTypes(t *testing.T) {
function verifySelectiveBufferOutput (line 199) | func verifySelectiveBufferOutput(t *testing.T, logOutput string) {
function verifySelectiveCallbackEntries (line 215) | func verifySelectiveCallbackEntries(t *testing.T, entries []*log.LogEntr...
function checkEntryActiveStatus (line 234) | func checkEntryActiveStatus(t *testing.T, entry *log.LogEntry) {
FILE: management_api.go
method GetAllSubjects (line 28) | func (e *Enforcer) GetAllSubjects() ([]string, error) {
method GetAllNamedSubjects (line 33) | func (e *Enforcer) GetAllNamedSubjects(ptype string) ([]string, error) {
method GetAllObjects (line 42) | func (e *Enforcer) GetAllObjects() ([]string, error) {
method GetAllNamedObjects (line 47) | func (e *Enforcer) GetAllNamedObjects(ptype string) ([]string, error) {
method GetAllActions (line 56) | func (e *Enforcer) GetAllActions() ([]string, error) {
method GetAllNamedActions (line 61) | func (e *Enforcer) GetAllNamedActions(ptype string) ([]string, error) {
method GetAllRoles (line 70) | func (e *Enforcer) GetAllRoles() ([]string, error) {
method GetAllNamedRoles (line 75) | func (e *Enforcer) GetAllNamedRoles(ptype string) ([]string, error) {
method GetAllUsers (line 81) | func (e *Enforcer) GetAllUsers() ([]string, error) {
method GetPolicy (line 97) | func (e *Enforcer) GetPolicy() ([][]string, error) {
method GetFilteredPolicy (line 102) | func (e *Enforcer) GetFilteredPolicy(fieldIndex int, fieldValues ...stri...
method GetNamedPolicy (line 107) | func (e *Enforcer) GetNamedPolicy(ptype string) ([][]string, error) {
method GetFilteredNamedPolicy (line 112) | func (e *Enforcer) GetFilteredNamedPolicy(ptype string, fieldIndex int, ...
method GetGroupingPolicy (line 117) | func (e *Enforcer) GetGroupingPolicy() ([][]string, error) {
method GetFilteredGroupingPolicy (line 122) | func (e *Enforcer) GetFilteredGroupingPolicy(fieldIndex int, fieldValues...
method GetNamedGroupingPolicy (line 127) | func (e *Enforcer) GetNamedGroupingPolicy(ptype string) ([][]string, err...
method GetFilteredNamedGroupingPolicy (line 132) | func (e *Enforcer) GetFilteredNamedGroupingPolicy(ptype string, fieldInd...
method GetFilteredNamedPolicyWithMatcher (line 137) | func (e *Enforcer) GetFilteredNamedPolicyWithMatcher(ptype string, match...
method HasPolicy (line 215) | func (e *Enforcer) HasPolicy(params ...interface{}) (bool, error) {
method HasNamedPolicy (line 220) | func (e *Enforcer) HasNamedPolicy(ptype string, params ...interface{}) (...
method AddPolicy (line 236) | func (e *Enforcer) AddPolicy(params ...interface{}) (bool, error) {
method AddPolicies (line 243) | func (e *Enforcer) AddPolicies(rules [][]string) (bool, error) {
method AddPoliciesEx (line 250) | func (e *Enforcer) AddPoliciesEx(rules [][]string) (bool, error) {
method AddNamedPolicy (line 257) | func (e *Enforcer) AddNamedPolicy(ptype string, params ...interface{}) (...
method AddNamedPolicies (line 273) | func (e *Enforcer) AddNamedPolicies(ptype string, rules [][]string) (boo...
method AddNamedPoliciesEx (line 280) | func (e *Enforcer) AddNamedPoliciesEx(ptype string, rules [][]string) (b...
method RemovePolicy (line 285) | func (e *Enforcer) RemovePolicy(params ...interface{}) (bool, error) {
method UpdatePolicy (line 290) | func (e *Enforcer) UpdatePolicy(oldPolicy []string, newPolicy []string) ...
method UpdateNamedPolicy (line 294) | func (e *Enforcer) UpdateNamedPolicy(ptype string, p1 []string, p2 []str...
method UpdatePolicies (line 299) | func (e *Enforcer) UpdatePolicies(oldPolices [][]string, newPolicies [][...
method UpdateNamedPolicies (line 303) | func (e *Enforcer) UpdateNamedPolicies(ptype string, p1 [][]string, p2 [...
method UpdateFilteredPolicies (line 307) | func (e *Enforcer) UpdateFilteredPolicies(newPolicies [][]string, fieldI...
method UpdateFilteredNamedPolicies (line 311) | func (e *Enforcer) UpdateFilteredNamedPolicies(ptype string, newPolicies...
method RemovePolicies (line 316) | func (e *Enforcer) RemovePolicies(rules [][]string) (bool, error) {
method RemoveFilteredPolicy (line 321) | func (e *Enforcer) RemoveFilteredPolicy(fieldIndex int, fieldValues ...s...
method RemoveNamedPolicy (line 326) | func (e *Enforcer) RemoveNamedPolicy(ptype string, params ...interface{}...
method RemoveNamedPolicies (line 339) | func (e *Enforcer) RemoveNamedPolicies(ptype string, rules [][]string) (...
method RemoveFilteredNamedPolicy (line 344) | func (e *Enforcer) RemoveFilteredNamedPolicy(ptype string, fieldIndex in...
method HasGroupingPolicy (line 349) | func (e *Enforcer) HasGroupingPolicy(params ...interface{}) (bool, error) {
method HasNamedGroupingPolicy (line 354) | func (e *Enforcer) HasNamedGroupingPolicy(ptype string, params ...interf...
method AddGroupingPolicy (line 370) | func (e *Enforcer) AddGroupingPolicy(params ...interface{}) (bool, error) {
method AddGroupingPolicies (line 377) | func (e *Enforcer) AddGroupingPolicies(rules [][]string) (bool, error) {
method AddGroupingPoliciesEx (line 384) | func (e *Enforcer) AddGroupingPoliciesEx(rules [][]string) (bool, error) {
method AddNamedGroupingPolicy (line 391) | func (e *Enforcer) AddNamedGroupingPolicy(ptype string, params ...interf...
method AddNamedGroupingPolicies (line 411) | func (e *Enforcer) AddNamedGroupingPolicies(ptype string, rules [][]stri...
method AddNamedGroupingPoliciesEx (line 418) | func (e *Enforcer) AddNamedGroupingPoliciesEx(ptype string, rules [][]st...
method RemoveGroupingPolicy (line 423) | func (e *Enforcer) RemoveGroupingPolicy(params ...interface{}) (bool, er...
method RemoveGroupingPolicies (line 428) | func (e *Enforcer) RemoveGroupingPolicies(rules [][]string) (bool, error) {
method RemoveFilteredGroupingPolicy (line 433) | func (e *Enforcer) RemoveFilteredGroupingPolicy(fieldIndex int, fieldVal...
method RemoveNamedGroupingPolicy (line 438) | func (e *Enforcer) RemoveNamedGroupingPolicy(ptype string, params ...int...
method RemoveNamedGroupingPolicies (line 456) | func (e *Enforcer) RemoveNamedGroupingPolicies(ptype string, rules [][]s...
method UpdateGroupingPolicy (line 460) | func (e *Enforcer) UpdateGroupingPolicy(oldRule []string, newRule []stri...
method UpdateGroupingPolicies (line 465) | func (e *Enforcer) UpdateGroupingPolicies(oldRules [][]string, newRules ...
method UpdateNamedGroupingPolicy (line 469) | func (e *Enforcer) UpdateNamedGroupingPolicy(ptype string, oldRule []str...
method UpdateNamedGroupingPolicies (line 473) | func (e *Enforcer) UpdateNamedGroupingPolicies(ptype string, oldRules []...
method RemoveFilteredNamedGroupingPolicy (line 478) | func (e *Enforcer) RemoveFilteredNamedGroupingPolicy(ptype string, field...
method AddFunction (line 483) | func (e *Enforcer) AddFunction(name string, function govaluate.Expressio...
method SelfAddPolicy (line 487) | func (e *Enforcer) SelfAddPolicy(sec string, ptype string, rule []string...
method SelfAddPolicies (line 491) | func (e *Enforcer) SelfAddPolicies(sec string, ptype string, rules [][]s...
method SelfAddPoliciesEx (line 495) | func (e *Enforcer) SelfAddPoliciesEx(sec string, ptype string, rules [][...
method SelfRemovePolicy (line 499) | func (e *Enforcer) SelfRemovePolicy(sec string, ptype string, rule []str...
method SelfRemovePolicies (line 503) | func (e *Enforcer) SelfRemovePolicies(sec string, ptype string, rules []...
method SelfRemoveFilteredPolicy (line 507) | func (e *Enforcer) SelfRemoveFilteredPolicy(sec string, ptype string, fi...
method SelfUpdatePolicy (line 511) | func (e *Enforcer) SelfUpdatePolicy(sec string, ptype string, oldRule, n...
method SelfUpdatePolicies (line 515) | func (e *Enforcer) SelfUpdatePolicies(sec string, ptype string, oldRules...
FILE: management_api_b_test.go
function BenchmarkHasPolicySmall (line 22) | func BenchmarkHasPolicySmall(b *testing.B) {
function BenchmarkHasPolicyMedium (line 36) | func BenchmarkHasPolicyMedium(b *testing.B) {
function BenchmarkHasPolicyLarge (line 54) | func BenchmarkHasPolicyLarge(b *testing.B) {
function BenchmarkAddPolicySmall (line 73) | func BenchmarkAddPolicySmall(b *testing.B) {
function BenchmarkAddPolicyMedium (line 87) | func BenchmarkAddPolicyMedium(b *testing.B) {
function BenchmarkAddPolicyLarge (line 105) | func BenchmarkAddPolicyLarge(b *testing.B) {
function BenchmarkRemovePolicySmall (line 124) | func BenchmarkRemovePolicySmall(b *testing.B) {
function BenchmarkRemovePolicyMedium (line 138) | func BenchmarkRemovePolicyMedium(b *testing.B) {
function BenchmarkRemovePolicyLarge (line 157) | func BenchmarkRemovePolicyLarge(b *testing.B) {
FILE: management_api_test.go
function testStringList (line 23) | func testStringList(t *testing.T, title string, f func() ([]string, erro...
function TestGetList (line 37) | func TestGetList(t *testing.T) {
function TestGetListWithDomains (line 47) | func TestGetListWithDomains(t *testing.T) {
function testGetPolicy (line 57) | func testGetPolicy(t *testing.T, e *Enforcer, res [][]string) {
function testGetFilteredPolicy (line 71) | func testGetFilteredPolicy(t *testing.T, e *Enforcer, fieldIndex int, re...
function testGetFilteredNamedPolicyWithMatcher (line 85) | func testGetFilteredNamedPolicyWithMatcher(t *testing.T, e *Enforcer, pt...
function testGetGroupingPolicy (line 99) | func testGetGroupingPolicy(t *testing.T, e *Enforcer, res [][]string) {
function testGetFilteredGroupingPolicy (line 113) | func testGetFilteredGroupingPolicy(t *testing.T, e *Enforcer, fieldIndex...
function testHasPolicy (line 127) | func testHasPolicy(t *testing.T, e *Enforcer, policy []string, res bool) {
function testHasGroupingPolicy (line 141) | func testHasGroupingPolicy(t *testing.T, e *Enforcer, policy []string, r...
function TestGetPolicyAPI (line 155) | func TestGetPolicyAPI(t *testing.T) {
function TestModifyPolicyAPI (line 202) | func TestModifyPolicyAPI(t *testing.T) {
function TestModifyGroupingPolicyAPI (line 283) | func TestModifyGroupingPolicyAPI(t *testing.T) {
FILE: model/assertion.go
type Assertion (line 27) | type Assertion struct
method buildIncrementalRoleLinks (line 40) | func (ast *Assertion) buildIncrementalRoleLinks(rm rbac.RoleManager, o...
method buildRoleLinks (line 70) | func (ast *Assertion) buildRoleLinks(rm rbac.RoleManager) error {
method buildIncrementalConditionalRoleLinks (line 92) | func (ast *Assertion) buildIncrementalConditionalRoleLinks(condRM rbac...
method buildConditionalRoleLinks (line 124) | func (ast *Assertion) buildConditionalRoleLinks(condRM rbac.Conditiona...
method addConditionalRoleLink (line 150) | func (ast *Assertion) addConditionalRoleLink(rule []string, domainRule...
method copy (line 167) | func (ast *Assertion) copy() *Assertion {
FILE: model/constraint.go
type ConstraintType (line 27) | type ConstraintType
constant ConstraintTypeSOD (line 30) | ConstraintTypeSOD ConstraintType = iota
constant ConstraintTypeSODMax (line 31) | ConstraintTypeSODMax
constant ConstraintTypeRoleMax (line 32) | ConstraintTypeRoleMax
constant ConstraintTypeRolePre (line 33) | ConstraintTypeRolePre
type Constraint (line 37) | type Constraint struct
function parseRolesArray (line 55) | func parseRolesArray(rolesStr string) ([]string, error) {
function parseConstraint (line 73) | func parseConstraint(key, value string) (*Constraint, error) {
method ValidateConstraints (line 133) | func (model Model) ValidateConstraints() error {
method validateConstraint (line 166) | func (model Model) validateConstraint(constraint *Constraint, groupingPo...
function buildUserRoleMap (line 182) | func buildUserRoleMap(groupingPolicy [][]string) map[string]map[string]b...
method validateSOD (line 202) | func (model Model) validateSOD(constraint *Constraint, groupingPolicy []...
method validateSODMax (line 222) | func (model Model) validateSODMax(constraint *Constraint, groupingPolicy...
method validateRoleMax (line 244) | func (model Model) validateRoleMax(constraint *Constraint, groupingPolic...
method validateRolePre (line 269) | func (model Model) validateRolePre(constraint *Constraint, groupingPolic...
FILE: model/function.go
type FunctionMap (line 25) | type FunctionMap struct
method AddFunction (line 32) | func (fm *FunctionMap) AddFunction(name string, function govaluate.Exp...
method GetFunctions (line 57) | func (fm *FunctionMap) GetFunctions() map[string]govaluate.ExpressionF...
function LoadFunctionMap (line 37) | func LoadFunctionMap() FunctionMap {
FILE: model/model.go
type Model (line 32) | type Model
method AddDef (line 70) | func (model Model) AddDef(sec string, key string, value string) bool {
method LoadModel (line 163) | func (model Model) LoadModel(path string) error {
method LoadModelFromText (line 173) | func (model Model) LoadModelFromText(text string) error {
method loadModelFromConfig (line 187) | func (model Model) loadModelFromConfig(cfg config.ConfigInterface) err...
method hasSection (line 209) | func (model Model) hasSection(sec string) bool {
method GetAssertion (line 214) | func (model Model) GetAssertion(sec string, ptype string) (*Assertion,...
method PrintModel (line 225) | func (model Model) PrintModel() {
method SortPoliciesBySubjectHierarchy (line 229) | func (model Model) SortPoliciesBySubjectHierarchy() error {
method SortPoliciesByPriority (line 321) | func (model Model) SortPoliciesByPriority() error {
method ToText (line 351) | func (model Model) ToText() string {
method Copy (line 395) | func (model Model) Copy() Model {
method GetFieldIndex (line 409) | func (model Model) GetFieldIndex(ptype string, field string) (int, err...
type AssertionMap (line 35) | type AssertionMap
constant defaultDomain (line 37) | defaultDomain string = ""
constant defaultSeparator (line 38) | defaultSeparator = "::"
function loadAssertion (line 52) | func loadAssertion(model Model, cfg config.ConfigInterface, sec string, ...
function getParamsToken (line 60) | func getParamsToken(value string) []string {
function getKeySuffix (line 112) | func getKeySuffix(i int) string {
function loadSection (line 120) | func loadSection(model Model, cfg config.ConfigInterface, sec string) {
function NewModel (line 132) | func NewModel() Model {
function NewModelFromFile (line 139) | func NewModelFromFile(path string) (Model, error) {
function NewModelFromString (line 151) | func NewModelFromString(text string) (Model, error) {
function getSubjectHierarchyMap (line 266) | func getSubjectHierarchyMap(policies [][]string) (map[string]int, error) {
function getNameWithDomain (line 317) | func getNameWithDomain(domain string, name string) string {
FILE: model/model_test.go
type MockConfig (line 39) | type MockConfig struct
method String (line 44) | func (mc *MockConfig) String(key string) string {
function TestNewModel (line 48) | func TestNewModel(t *testing.T) {
function TestNewModelFromFile (line 55) | func TestNewModelFromFile(t *testing.T) {
function TestNewModelFromString (line 65) | func TestNewModelFromString(t *testing.T) {
function TestLoadModelFromConfig (line 77) | func TestLoadModelFromConfig(t *testing.T) {
function TestHasSection (line 97) | func TestHasSection(t *testing.T) {
function TestModel_AddDef (line 114) | func TestModel_AddDef(t *testing.T) {
function TestModelToTest (line 128) | func TestModelToTest(t *testing.T) {
function testModelToText (line 133) | func testModelToText(t *testing.T, mData, mExpected string) {
FILE: model/policy.go
type PolicyOp (line 28) | type PolicyOp
constant PolicyAdd (line 32) | PolicyAdd PolicyOp = iota
constant PolicyRemove (line 33) | PolicyRemove
constant DefaultSep (line 36) | DefaultSep = ","
method BuildIncrementalRoleLinks (line 39) | func (model Model) BuildIncrementalRoleLinks(rmMap map[string]rbac.RoleM...
method BuildRoleLinks (line 51) | func (model Model) BuildRoleLinks(rmMap map[string]rbac.RoleManager) err...
method BuildIncrementalConditionalRoleLinks (line 66) | func (model Model) BuildIncrementalConditionalRoleLinks(condRmMap map[st...
method BuildConditionalRoleLinks (line 78) | func (model Model) BuildConditionalRoleLinks(condRmMap map[string]rbac.C...
method PrintPolicy (line 93) | func (model Model) PrintPolicy() {
method ClearPolicy (line 98) | func (model Model) ClearPolicy() {
method GetPolicy (line 111) | func (model Model) GetPolicy(sec string, ptype string) ([][]string, erro...
method GetFilteredPolicy (line 120) | func (model Model) GetFilteredPolicy(sec string, ptype string, fieldInde...
method HasPolicyEx (line 145) | func (model Model) HasPolicyEx(sec string, ptype string, rule []string) ...
method HasPolicy (line 172) | func (model Model) HasPolicy(sec string, ptype string, rule []string) (b...
method HasPolicies (line 182) | func (model Model) HasPolicies(sec string, ptype string, rules [][]strin...
method AddPolicy (line 197) | func (model Model) AddPolicy(sec string, ptype string, rule []string) er...
method AddPolicies (line 228) | func (model Model) AddPolicies(sec string, ptype string, rules [][]strin...
method AddPoliciesWithAffected (line 234) | func (model Model) AddPoliciesWithAffected(sec string, ptype string, rul...
method RemovePolicy (line 257) | func (model Model) RemovePolicy(sec string, ptype string, rule []string)...
method UpdatePolicy (line 280) | func (model Model) UpdatePolicy(sec string, ptype string, oldRule []stri...
method UpdatePolicies (line 299) | func (model Model) UpdatePolicies(sec string, ptype string, oldRules, ne...
method RemovePolicies (line 340) | func (model Model) RemovePolicies(sec string, ptype string, rules [][]st...
method RemovePoliciesWithAffected (line 346) | func (model Model) RemovePoliciesWithAffected(sec string, ptype string, ...
method RemoveFilteredPolicy (line 369) | func (model Model) RemoveFilteredPolicy(sec string, ptype string, fieldI...
method GetValuesForFieldInPolicy (line 405) | func (model Model) GetValuesForFieldInPolicy(sec string, ptype string, f...
method GetValuesForFieldInPolicyAllTypes (line 423) | func (model Model) GetValuesForFieldInPolicyAllTypes(sec string, fieldIn...
method GetValuesForFieldInPolicyAllTypesByName (line 440) | func (model Model) GetValuesForFieldInPolicyAllTypesByName(sec string, f...
FILE: model_b_test.go
function rawEnforce (line 24) | func rawEnforce(sub string, obj string, act string) bool {
function BenchmarkRaw (line 34) | func BenchmarkRaw(b *testing.B) {
function BenchmarkBasicModel (line 40) | func BenchmarkBasicModel(b *testing.B) {
function BenchmarkRBACModel (line 49) | func BenchmarkRBACModel(b *testing.B) {
function BenchmarkRBACModelSizes (line 58) | func BenchmarkRBACModelSizes(b *testing.B) {
function BenchmarkRBACModelSmall (line 127) | func BenchmarkRBACModelSmall(b *testing.B) {
function BenchmarkRBACModelMedium (line 152) | func BenchmarkRBACModelMedium(b *testing.B) {
function BenchmarkRBACModelLarge (line 183) | func BenchmarkRBACModelLarge(b *testing.B) {
function BenchmarkRBACModelWithResourceRoles (line 214) | func BenchmarkRBACModelWithResourceRoles(b *testing.B) {
function BenchmarkRBACModelWithDomains (line 223) | func BenchmarkRBACModelWithDomains(b *testing.B) {
function BenchmarkABACModel (line 232) | func BenchmarkABACModel(b *testing.B) {
function BenchmarkABACRuleModel (line 242) | func BenchmarkABACRuleModel(b *testing.B) {
function BenchmarkKeyMatchModel (line 256) | func BenchmarkKeyMatchModel(b *testing.B) {
function BenchmarkRBACModelWithDeny (line 265) | func BenchmarkRBACModelWithDeny(b *testing.B) {
function BenchmarkPriorityModel (line 274) | func BenchmarkPriorityModel(b *testing.B) {
function BenchmarkRBACModelWithDomainPatternLarge (line 283) | func BenchmarkRBACModelWithDomainPatternLarge(b *testing.B) {
FILE: model_test.go
function testEnforce (line 26) | func testEnforce(t *testing.T, e *Enforcer, sub interface{}, obj interfa...
function testEnforceWithoutUsers (line 35) | func testEnforceWithoutUsers(t *testing.T, e *Enforcer, obj string, act ...
function testDomainEnforce (line 42) | func testDomainEnforce(t *testing.T, e *Enforcer, sub string, dom string...
function TestBasicModel (line 51) | func TestBasicModel(t *testing.T) {
function TestBasicModelWithoutSpaces (line 64) | func TestBasicModelWithoutSpaces(t *testing.T) {
function TestBasicModelNoPolicy (line 77) | func TestBasicModelNoPolicy(t *testing.T) {
function TestBasicModelWithRoot (line 90) | func TestBasicModelWithRoot(t *testing.T) {
function TestBasicModelWithRootNoPolicy (line 107) | func TestBasicModelWithRootNoPolicy(t *testing.T) {
function TestBasicModelWithoutUsers (line 124) | func TestBasicModelWithoutUsers(t *testing.T) {
function TestBasicModelWithoutResources (line 133) | func TestBasicModelWithoutResources(t *testing.T) {
function TestRBACModel (line 142) | func TestRBACModel(t *testing.T) {
function TestRBACModelWithResourceRoles (line 155) | func TestRBACModelWithResourceRoles(t *testing.T) {
function TestRBACModelWithDomains (line 168) | func TestRBACModelWithDomains(t *testing.T) {
function TestRBACModelWithDomainsAtRuntime (line 181) | func TestRBACModelWithDomainsAtRuntime(t *testing.T) {
function TestRBACModelWithDomainsAtRuntimeMockAdapter (line 226) | func TestRBACModelWithDomainsAtRuntimeMockAdapter(t *testing.T) {
function TestRBACModelWithDomainTokenRename (line 244) | func TestRBACModelWithDomainTokenRename(t *testing.T) {
function TestRBACModelWithDeny (line 325) | func TestRBACModelWithDeny(t *testing.T) {
function TestRBACModelWithOnlyDeny (line 338) | func TestRBACModelWithOnlyDeny(t *testing.T) {
function TestRBACModelWithCustomData (line 344) | func TestRBACModelWithCustomData(t *testing.T) {
function TestRBACModelWithPattern (line 376) | func TestRBACModelWithPattern(t *testing.T) {
function TestRBACModelWithDifferentTypesOfRoles (line 413) | func TestRBACModelWithDifferentTypesOfRoles(t *testing.T) {
type testCustomRoleManager (line 442) | type testCustomRoleManager struct
method Clear (line 447) | func (rm *testCustomRoleManager) Clear() error { return nil }
method AddLink (line 448) | func (rm *testCustomRoleManager) AddLink(name1 string, name2 string, d...
method BuildRelationship (line 451) | func (rm *testCustomRoleManager) BuildRelationship(name1 string, name2...
method DeleteLink (line 454) | func (rm *testCustomRoleManager) DeleteLink(name1 string, name2 string...
method HasLink (line 457) | func (rm *testCustomRoleManager) HasLink(name1 string, name2 string, d...
method GetRoles (line 467) | func (rm *testCustomRoleManager) GetRoles(name string, domain ...strin...
method GetUsers (line 470) | func (rm *testCustomRoleManager) GetUsers(name string, domain ...strin...
method GetDomains (line 473) | func (rm *testCustomRoleManager) GetDomains(name string) ([]string, er...
method GetAllDomains (line 476) | func (rm *testCustomRoleManager) GetAllDomains() ([]string, error) {
method PrintRoles (line 479) | func (rm *testCustomRoleManager) PrintRoles() error { return nil }
method Match (line 481) | func (rm *testCustomRoleManager) Match(str string, pattern string) boo...
method AddMatchingFunc (line 482) | func (rm *testCustomRoleManager) AddMatchingFunc(name string, fn rbac....
method AddDomainMatchingFunc (line 483) | func (rm *testCustomRoleManager) AddDomainMatchingFunc(name string, fn...
method AddLinkConditionFunc (line 485) | func (rm *testCustomRoleManager) AddLinkConditionFunc(userName, roleNa...
method SetLinkConditionFuncParams (line 487) | func (rm *testCustomRoleManager) SetLinkConditionFuncParams(userName, ...
method AddDomainLinkConditionFunc (line 489) | func (rm *testCustomRoleManager) AddDomainLinkConditionFunc(user strin...
method SetDomainLinkConditionFuncParams (line 491) | func (rm *testCustomRoleManager) SetDomainLinkConditionFuncParams(user...
method DeleteDomain (line 494) | func (rm *testCustomRoleManager) DeleteDomain(domain string) error {
method GetImplicitRoles (line 498) | func (rm *testCustomRoleManager) GetImplicitRoles(name string, domain ...
method GetImplicitUsers (line 502) | func (rm *testCustomRoleManager) GetImplicitUsers(name string, domain ...
function NewRoleManager (line 444) | func NewRoleManager() rbac.RoleManager {
function TestRBACModelWithCustomRoleManager (line 506) | func TestRBACModelWithCustomRoleManager(t *testing.T) {
function TestKeyMatchModel (line 522) | func TestKeyMatchModel(t *testing.T) {
function TestKeyMatch2Model (line 548) | func TestKeyMatch2Model(t *testing.T) {
function CustomFunction (line 557) | func CustomFunction(key1 string, key2 string) bool {
function CustomFunctionWrapper (line 567) | func CustomFunctionWrapper(args ...interface{}) (interface{}, error) {
function TestKeyMatchCustomModel (line 574) | func TestKeyMatchCustomModel(t *testing.T) {
function TestIPMatchModel (line 583) | func TestIPMatchModel(t *testing.T) {
function TestGlobMatchModel (line 607) | func TestGlobMatchModel(t *testing.T) {
function TestPriorityModel (line 626) | func TestPriorityModel(t *testing.T) {
function TestPriorityModelIndeterminate (line 639) | func TestPriorityModelIndeterminate(t *testing.T) {
function TestRBACModelInMultiLines (line 645) | func TestRBACModelInMultiLines(t *testing.T) {
function TestCommentModel (line 658) | func TestCommentModel(t *testing.T) {
function TestDomainMatchModel (line 670) | func TestDomainMatchModel(t *testing.T) {
function TestAllMatchModel (line 686) | func TestAllMatchModel(t *testing.T) {
function TestTemporalRolesModel (line 697) | func TestTemporalRolesModel(t *testing.T) {
function TestTemporalRolesModelWithDomain (line 726) | func TestTemporalRolesModelWithDomain(t *testing.T) {
function TestReBACModel (line 772) | func TestReBACModel(t *testing.T) {
FILE: orbac_test.go
function testEnforceOrBAC (line 32) | func testEnforceOrBAC(t *testing.T, e *Enforcer, sub string, org string,...
function TestOrBACModel (line 41) | func TestOrBACModel(t *testing.T) {
FILE: pbac_test.go
function testEnforcePBAC (line 22) | func testEnforcePBAC(t *testing.T, e *Enforcer, sub interface{}, obj int...
function TestPBACModel (line 34) | func TestPBACModel(t *testing.T) {
FILE: persist/adapter.go
function LoadPolicyLine (line 25) | func LoadPolicyLine(line string, m model.Model) error {
function LoadPolicyArray (line 44) | func LoadPolicyArray(rule []string, m model.Model) error {
type Adapter (line 64) | type Adapter interface
FILE: persist/adapter_context.go
type ContextAdapter (line 24) | type ContextAdapter interface
FILE: persist/adapter_filtered.go
type FilteredAdapter (line 22) | type FilteredAdapter interface
FILE: persist/adapter_filtered_context.go
type ContextFilteredAdapter (line 24) | type ContextFilteredAdapter interface
FILE: persist/batch_adapter.go
type BatchAdapter (line 18) | type BatchAdapter interface
FILE: persist/batch_adapter_context.go
type ContextBatchAdapter (line 20) | type ContextBatchAdapter interface
FILE: persist/cache/cache.go
type Cache (line 21) | type Cache interface
FILE: persist/cache/cache_sync.go
type SyncCache (line 22) | type SyncCache struct
method Set (line 27) | func (c *SyncCache) Set(key string, value bool, extra ...interface{}) ...
method Get (line 42) | func (c *SyncCache) Get(key string) (bool, error) {
method Delete (line 59) | func (c *SyncCache) Delete(key string) error {
method Clear (line 73) | func (c *SyncCache) Clear() error {
function NewSyncCache (line 80) | func NewSyncCache() (Cache, error) {
FILE: persist/cache/default-cache.go
type cacheItem (line 19) | type cacheItem struct
type DefaultCache (line 25) | type DefaultCache
method Set (line 27) | func (c *DefaultCache) Set(key string, value bool, extra ...interface{...
method Get (line 40) | func (c *DefaultCache) Get(key string) (bool, error) {
method Delete (line 52) | func (c *DefaultCache) Delete(key string) error {
method Clear (line 61) | func (c *DefaultCache) Clear() error {
function NewDefaultCache (line 66) | func NewDefaultCache() (Cache, error) {
FILE: persist/dispatcher.go
type Dispatcher (line 18) | type Dispatcher interface
FILE: persist/file-adapter/adapter.go
type Adapter (line 31) | type Adapter struct
method UpdatePolicy (line 35) | func (a *Adapter) UpdatePolicy(sec string, ptype string, oldRule, newR...
method UpdatePolicies (line 39) | func (a *Adapter) UpdatePolicies(sec string, ptype string, oldRules, n...
method UpdateFilteredPolicies (line 43) | func (a *Adapter) UpdateFilteredPolicies(sec string, ptype string, new...
method LoadPolicy (line 53) | func (a *Adapter) LoadPolicy(model model.Model) error {
method SavePolicy (line 62) | func (a *Adapter) SavePolicy(model model.Model) error {
method loadPolicyFile (line 88) | func (a *Adapter) loadPolicyFile(model model.Model, handler func(strin...
method savePolicyFile (line 106) | func (a *Adapter) savePolicyFile(text string) error {
method AddPolicy (line 127) | func (a *Adapter) AddPolicy(sec string, ptype string, rule []string) e...
method AddPolicies (line 132) | func (a *Adapter) AddPolicies(sec string, ptype string, rules [][]stri...
method RemovePolicy (line 137) | func (a *Adapter) RemovePolicy(sec string, ptype string, rule []string...
method RemovePolicies (line 142) | func (a *Adapter) RemovePolicies(sec string, ptype string, rules [][]s...
method RemoveFilteredPolicy (line 147) | func (a *Adapter) RemoveFilteredPolicy(sec string, ptype string, field...
function NewAdapter (line 48) | func NewAdapter(filePath string) *Adapter {
FILE: persist/file-adapter/adapter_context.go
method UpdatePolicyCtx (line 23) | func (a *Adapter) UpdatePolicyCtx(ctx context.Context, sec string, ptype...
method UpdatePoliciesCtx (line 31) | func (a *Adapter) UpdatePoliciesCtx(ctx context.Context, sec string, pty...
method UpdateFilteredPoliciesCtx (line 39) | func (a *Adapter) UpdateFilteredPoliciesCtx(ctx context.Context, sec str...
method LoadPolicyCtx (line 48) | func (a *Adapter) LoadPolicyCtx(ctx context.Context, model model.Model) ...
method SavePolicyCtx (line 57) | func (a *Adapter) SavePolicyCtx(ctx context.Context, model model.Model) ...
method AddPolicyCtx (line 66) | func (a *Adapter) AddPolicyCtx(ctx context.Context, sec string, ptype st...
method AddPoliciesCtx (line 75) | func (a *Adapter) AddPoliciesCtx(ctx context.Context, sec string, ptype ...
method RemovePolicyCtx (line 84) | func (a *Adapter) RemovePolicyCtx(ctx context.Context, sec string, ptype...
method RemovePoliciesCtx (line 93) | func (a *Adapter) RemovePoliciesCtx(ctx context.Context, sec string, pty...
method RemoveFilteredPolicyCtx (line 102) | func (a *Adapter) RemoveFilteredPolicyCtx(ctx context.Context, sec strin...
function checkCtx (line 110) | func checkCtx(ctx context.Context) error {
FILE: persist/file-adapter/adapter_filtered.go
type FilteredAdapter (line 29) | type FilteredAdapter struct
method LoadPolicy (line 55) | func (a *FilteredAdapter) LoadPolicy(model model.Model) error {
method LoadFilteredPolicy (line 61) | func (a *FilteredAdapter) LoadFilteredPolicy(model model.Model, filter...
method loadFilteredPolicyFile (line 80) | func (a *FilteredAdapter) loadFilteredPolicyFile(model model.Model, fi...
method IsFiltered (line 104) | func (a *FilteredAdapter) IsFiltered() bool {
method SavePolicy (line 109) | func (a *FilteredAdapter) SavePolicy(model model.Model) error {
type Filter (line 36) | type Filter struct
function NewFilteredAdapter (line 47) | func NewFilteredAdapter(filePath string) *FilteredAdapter {
function filterLine (line 116) | func filterLine(line string, filter *Filter) bool {
function filterWords (line 144) | func filterWords(line []string, filter []string) bool {
FILE: persist/file-adapter/adapter_filtered_context.go
method LoadPolicyCtx (line 24) | func (a *FilteredAdapter) LoadPolicyCtx(ctx context.Context, model model...
method LoadFilteredPolicyCtx (line 33) | func (a *FilteredAdapter) LoadFilteredPolicyCtx(ctx context.Context, mod...
method SavePolicyCtx (line 42) | func (a *FilteredAdapter) SavePolicyCtx(ctx context.Context, model model...
method IsFilteredCtx (line 51) | func (a *FilteredAdapter) IsFilteredCtx(ctx context.Context) bool {
FILE: persist/file-adapter/adapter_mock.go
type AdapterMock (line 30) | type AdapterMock struct
method LoadPolicy (line 43) | func (a *AdapterMock) LoadPolicy(model model.Model) error {
method SavePolicy (line 49) | func (a *AdapterMock) SavePolicy(model model.Model) error {
method loadPolicyFile (line 53) | func (a *AdapterMock) loadPolicyFile(model model.Model, handler func(s...
method SetMockErr (line 77) | func (a *AdapterMock) SetMockErr(errorToSet string) {
method GetMockErr (line 82) | func (a *AdapterMock) GetMockErr() error {
method AddPolicy (line 91) | func (a *AdapterMock) AddPolicy(sec string, ptype string, rule []strin...
method AddPolicies (line 96) | func (a *AdapterMock) AddPolicies(sec string, ptype string, rules [][]...
method RemovePolicy (line 101) | func (a *AdapterMock) RemovePolicy(sec string, ptype string, rule []st...
method RemovePolicies (line 106) | func (a *AdapterMock) RemovePolicies(sec string, ptype string, rules [...
method UpdatePolicy (line 111) | func (a *AdapterMock) UpdatePolicy(sec string, ptype string, oldRule, ...
method UpdatePolicies (line 115) | func (a *AdapterMock) UpdatePolicies(sec string, ptype string, oldRule...
method RemoveFilteredPolicy (line 120) | func (a *AdapterMock) RemoveFilteredPolicy(sec string, ptype string, f...
function NewAdapterMock (line 36) | func NewAdapterMock(filePath string) *AdapterMock {
FILE: persist/persist_test.go
function TestPersist (line 25) | func TestPersist(t *testing.T) {
function testRuleCount (line 29) | func testRuleCount(t *testing.T, model model.Model, expected int, sec st...
function TestDuplicateRuleInAdapter (line 38) | func TestDuplicateRuleInAdapter(t *testing.T) {
FILE: persist/string-adapter/adapter.go
type Adapter (line 29) | type Adapter struct
method LoadPolicy (line 41) | func (a *Adapter) LoadPolicy(model model.Model) error {
method SavePolicy (line 57) | func (a *Adapter) SavePolicy(model model.Model) error {
method AddPolicy (line 79) | func (a *Adapter) AddPolicy(sec string, ptype string, rule []string) e...
method RemovePolicy (line 84) | func (a *Adapter) RemovePolicy(sec string, ptype string, rule []string...
method RemoveFilteredPolicy (line 90) | func (a *Adapter) RemoveFilteredPolicy(sec string, ptype string, field...
function NewAdapter (line 34) | func NewAdapter(line string) *Adapter {
FILE: persist/string-adapter/adapter_context.go
method LoadPolicyCtx (line 24) | func (a *Adapter) LoadPolicyCtx(ctx context.Context, model model.Model) ...
method SavePolicyCtx (line 33) | func (a *Adapter) SavePolicyCtx(ctx context.Context, model model.Model) ...
method AddPolicyCtx (line 42) | func (a *Adapter) AddPolicyCtx(ctx context.Context, sec string, ptype st...
method RemovePolicyCtx (line 51) | func (a *Adapter) RemovePolicyCtx(ctx context.Context, sec string, ptype...
method RemoveFilteredPolicyCtx (line 60) | func (a *Adapter) RemoveFilteredPolicyCtx(ctx context.Context, sec strin...
function checkCtx (line 68) | func checkCtx(ctx context.Context) error {
FILE: persist/string-adapter/adapter_test.go
function Test_KeyMatchRbac (line 24) | func Test_KeyMatchRbac(t *testing.T) {
function Test_StringRbac (line 64) | func Test_StringRbac(t *testing.T) {
FILE: persist/transaction.go
type TransactionalAdapter (line 21) | type TransactionalAdapter interface
type TransactionContext (line 30) | type TransactionContext interface
type PolicyOperation (line 40) | type PolicyOperation struct
type OperationType (line 49) | type OperationType
constant OperationAdd (line 53) | OperationAdd OperationType = iota
constant OperationRemove (line 55) | OperationRemove
constant OperationUpdate (line 57) | OperationUpdate
FILE: persist/update_adapter.go
type UpdatableAdapter (line 18) | type UpdatableAdapter interface
FILE: persist/update_adapter_context.go
type ContextUpdatableAdapter (line 20) | type ContextUpdatableAdapter interface
FILE: persist/watcher.go
type Watcher (line 18) | type Watcher interface
FILE: persist/watcher_ex.go
type WatcherEx (line 20) | type WatcherEx interface
FILE: persist/watcher_update.go
type UpdatableWatcher (line 18) | type UpdatableWatcher interface
FILE: rbac/context_role_manager.go
type ContextRoleManager (line 22) | type ContextRoleManager interface
FILE: rbac/default-role-manager/role_manager.go
constant defaultDomain (line 25) | defaultDomain string = ""
type Role (line 28) | type Role struct
method addRole (line 50) | func (r *Role) addRole(role *Role) {
method removeRole (line 55) | func (r *Role) removeRole(role *Role) {
method addUser (line 61) | func (r *Role) addUser(user *Role) {
method removeUser (line 66) | func (r *Role) removeUser(user *Role) {
method addMatch (line 70) | func (r *Role) addMatch(role *Role) {
method removeMatch (line 75) | func (r *Role) removeMatch(role *Role) {
method removeMatches (line 80) | func (r *Role) removeMatches() {
method rangeRoles (line 91) | func (r *Role) rangeRoles(fn func(key, value interface{}) bool) {
method rangeUsers (line 105) | func (r *Role) rangeUsers(fn func(key, value interface{}) bool) {
method getRoles (line 119) | func (r *Role) getRoles() []string {
method getUsers (line 128) | func (r *Role) getUsers() []string {
method addLinkConditionFunc (line 142) | func (r *Role) addLinkConditionFunc(role *Role, domain string, fn rbac...
method getLinkConditionFunc (line 146) | func (r *Role) getLinkConditionFunc(role *Role, domain string) (rbac.L...
method setLinkConditionFuncParams (line 154) | func (r *Role) setLinkConditionFuncParams(role *Role, domain string, p...
method getLinkConditionFuncParams (line 158) | func (r *Role) getLinkConditionFuncParams(role *Role, domain string) (...
function newRole (line 38) | func newRole(name string) *Role {
type linkConditionFuncKey (line 137) | type linkConditionFuncKey struct
type RoleManagerImpl (line 167) | type RoleManagerImpl struct
method rebuild (line 193) | func (rm *RoleManagerImpl) rebuild() {
method Match (line 202) | func (rm *RoleManagerImpl) Match(str string, pattern string) bool {
method rangeMatchingRoles (line 214) | func (rm *RoleManagerImpl) rangeMatchingRoles(name string, isPattern b...
method load (line 226) | func (rm *RoleManagerImpl) load(name interface{}) (value *Role, ok boo...
method getRole (line 234) | func (rm *RoleManagerImpl) getRole(name string) (r *Role, created bool) {
method removeRole (line 266) | func (rm *RoleManagerImpl) removeRole(name string) {
method AddMatchingFunc (line 273) | func (rm *RoleManagerImpl) AddMatchingFunc(name string, fn rbac.Matchi...
method AddDomainMatchingFunc (line 279) | func (rm *RoleManagerImpl) AddDomainMatchingFunc(name string, fn rbac....
method Clear (line 284) | func (rm *RoleManagerImpl) Clear() error {
method AddLink (line 292) | func (rm *RoleManagerImpl) AddLink(name1 string, name2 string, domains...
method DeleteLink (line 301) | func (rm *RoleManagerImpl) DeleteLink(name1 string, name2 string, doma...
method HasLink (line 309) | func (rm *RoleManagerImpl) HasLink(name1 string, name2 string, domains...
method hasLinkHelper (line 331) | func (rm *RoleManagerImpl) hasLinkHelper(targetName string, roles map[...
method GetRoles (line 351) | func (rm *RoleManagerImpl) GetRoles(name string, domains ...string) ([...
method GetUsers (line 361) | func (rm *RoleManagerImpl) GetUsers(name string, domain ...string) ([]...
method GetImplicitRoles (line 370) | func (rm *RoleManagerImpl) GetImplicitRoles(name string, domain ...str...
method GetImplicitUsers (line 385) | func (rm *RoleManagerImpl) GetImplicitUsers(name string, domain ...str...
method getImplicitRolesHelper (line 400) | func (rm *RoleManagerImpl) getImplicitRolesHelper(roles map[string]*Ro...
method getImplicitUsersHelper (line 422) | func (rm *RoleManagerImpl) getImplicitUsersHelper(users map[string]*Ro...
method PrintRoles (line 444) | func (rm *RoleManagerImpl) PrintRoles() error {
method GetDomains (line 450) | func (rm *RoleManagerImpl) GetDomains(name string) ([]string, error) {
method GetAllDomains (line 456) | func (rm *RoleManagerImpl) GetAllDomains() ([]string, error) {
method copyFrom (line 461) | func (rm *RoleManagerImpl) copyFrom(other *RoleManagerImpl) {
method Range (line 479) | func (rm *RoleManagerImpl) Range(fn func(name1, name2 string, domain ....
method BuildRelationship (line 484) | func (rm *RoleManagerImpl) BuildRelationship(name1 string, name2 strin...
method DeleteDomain (line 749) | func (rm *RoleManagerImpl) DeleteDomain(domain string) error {
function NewRoleManagerImpl (line 178) | func NewRoleManagerImpl(maxHierarchyLevel int) *RoleManagerImpl {
function newRoleManagerWithMatchingFunc (line 186) | func newRoleManagerWithMatchingFunc(maxHierarchyLevel int, fn rbac.Match...
function loadAndDelete (line 258) | func loadAndDelete(m *sync.Map, name string) (value interface{}, loaded ...
function rangeLinks (line 468) | func rangeLinks(users *sync.Map, fn func(name1, name2 string, domain ......
type DomainManager (line 488) | type DomainManager struct
method AddMatchingFunc (line 506) | func (dm *DomainManager) AddMatchingFunc(name string, fn rbac.Matching...
method AddDomainMatchingFunc (line 515) | func (dm *DomainManager) AddDomainMatchingFunc(name string, fn rbac.Ma...
method rebuild (line 525) | func (dm *DomainManager) rebuild() {
method Clear (line 541) | func (dm *DomainManager) Clear() error {
method getDomain (line 547) | func (dm *DomainManager) getDomain(domains ...string) (domain string, ...
method Match (line 556) | func (dm *DomainManager) Match(str string, pattern string) bool {
method rangeAffectedRoleManagers (line 568) | func (dm *DomainManager) rangeAffectedRoleManagers(domain string, fn f...
method load (line 580) | func (dm *DomainManager) load(name interface{}) (value *RoleManagerImp...
method getRoleManager (line 588) | func (dm *DomainManager) getRoleManager(domain string, store bool) *Ro...
method AddLink (line 613) | func (dm *DomainManager) AddLink(name1 string, name2 string, domains ....
method DeleteLink (line 629) | func (dm *DomainManager) DeleteLink(name1 string, name2 string, domain...
method HasLink (line 644) | func (dm *DomainManager) HasLink(name1 string, name2 string, domains ....
method GetRoles (line 654) | func (dm *DomainManager) GetRoles(name string, domains ...string) ([]s...
method GetUsers (line 664) | func (dm *DomainManager) GetUsers(name string, domains ...string) ([]s...
method GetImplicitRoles (line 674) | func (dm *DomainManager) GetImplicitRoles(name string, domains ...stri...
method GetImplicitUsers (line 684) | func (dm *DomainManager) GetImplicitUsers(name string, domains ...stri...
method PrintRoles (line 694) | func (dm *DomainManager) PrintRoles() error {
method GetDomains (line 700) | func (dm *DomainManager) GetDomains(name string) ([]string, error) {
method GetAllDomains (line 718) | func (dm *DomainManager) GetAllDomains() ([]string, error) {
method BuildRelationship (line 728) | func (dm *DomainManager) BuildRelationship(name1 string, name2 string,...
method DeleteDomain (line 733) | func (dm *DomainManager) DeleteDomain(domain string) error {
function NewDomainManager (line 498) | func NewDomainManager(maxHierarchyLevel int) *DomainManager {
type RoleManager (line 738) | type RoleManager struct
function NewRoleManager (line 742) | func NewRoleManager(maxHierarchyLevel int) *RoleManager {
type ConditionalRoleManager (line 753) | type ConditionalRoleManager struct
method copyFrom (line 757) | func (crm *ConditionalRoleManager) copyFrom(other *ConditionalRoleMana...
method HasLink (line 781) | func (crm *ConditionalRoleManager) HasLink(name1 string, name2 string,...
method hasLinkHelper (line 805) | func (crm *ConditionalRoleManager) hasLinkHelper(targetName string, ro...
method getNextRoles (line 823) | func (crm *ConditionalRoleManager) getNextRoles(currentRole, nextRole ...
method checkLinkCondition (line 838) | func (crm *ConditionalRoleManager) checkLinkCondition(name1, name2 str...
method GetRoles (line 857) | func (crm *ConditionalRoleManager) GetRoles(name string, domains ...st...
method GetUsers (line 880) | func (crm *ConditionalRoleManager) GetUsers(name string, domains ...st...
method GetImplicitRoles (line 906) | func (crm *ConditionalRoleManager) GetImplicitRoles(name string, domai...
method GetImplicitUsers (line 921) | func (crm *ConditionalRoleManager) GetImplicitUsers(name string, domai...
method getImplicitRolesHelper (line 936) | func (crm *ConditionalRoleManager) getImplicitRolesHelper(roles map[st...
method getImplicitUsersHelper (line 966) | func (crm *ConditionalRoleManager) getImplicitUsersHelper(users map[st...
method GetLinkConditionFunc (line 996) | func (crm *ConditionalRoleManager) GetLinkConditionFunc(userName, role...
method GetDomainLinkConditionFunc (line 1001) | func (crm *ConditionalRoleManager) GetDomainLinkConditionFunc(userName...
method GetLinkConditionFuncParams (line 1019) | func (crm *ConditionalRoleManager) GetLinkConditionFuncParams(userName...
method AddLinkConditionFunc (line 1046) | func (crm *ConditionalRoleManager) AddLinkConditionFunc(userName, role...
method AddDomainLinkConditionFunc (line 1051) | func (crm *ConditionalRoleManager) AddDomainLinkConditionFunc(userName...
method SetLinkConditionFuncParams (line 1059) | func (crm *ConditionalRoleManager) SetLinkConditionFuncParams(userName...
method SetDomainLinkConditionFuncParams (line 1064) | func (crm *ConditionalRoleManager) SetDomainLinkConditionFuncParams(us...
function newConditionalRoleManagerWithMatchingFunc (line 765) | func newConditionalRoleManagerWithMatchingFunc(maxHierarchyLevel int, fn...
function NewConditionalRoleManager (line 773) | func NewConditionalRoleManager(maxHierarchyLevel int) *ConditionalRoleMa...
type ConditionalDomainManager (line 1071) | type ConditionalDomainManager struct
method load (line 1085) | func (cdm *ConditionalDomainManager) load(name interface{}) (value *Co...
method getConditionalRoleManager (line 1093) | func (cdm *ConditionalDomainManager) getConditionalRoleManager(domain ...
method HasLink (line 1117) | func (cdm *ConditionalDomainManager) HasLink(name1 string, name2 strin...
method GetRoles (line 1126) | func (cdm *ConditionalDomainManager) GetRoles(name string, domains ......
method GetUsers (line 1135) | func (cdm *ConditionalDomainManager) GetUsers(name string, domains ......
method GetImplicitRoles (line 1144) | func (cdm *ConditionalDomainManager) GetImplicitRoles(name string, dom...
method GetImplicitUsers (line 1153) | func (cdm *ConditionalDomainManager) GetImplicitUsers(name string, dom...
method AddLink (line 1164) | func (cdm *ConditionalDomainManager) AddLink(name1 string, name2 strin...
method DeleteLink (line 1180) | func (cdm *ConditionalDomainManager) DeleteLink(name1 string, name2 st...
method AddLinkConditionFunc (line 1195) | func (cdm *ConditionalDomainManager) AddLinkConditionFunc(userName, ro...
method AddDomainLinkConditionFunc (line 1203) | func (cdm *ConditionalDomainManager) AddDomainLinkConditionFunc(userNa...
method SetLinkConditionFuncParams (line 1211) | func (cdm *ConditionalDomainManager) SetLinkConditionFuncParams(userNa...
method SetDomainLinkConditionFuncParams (line 1219) | func (cdm *ConditionalDomainManager) SetDomainLinkConditionFuncParams(...
method AddDomainMatchingFunc (line 1227) | func (cdm *ConditionalDomainManager) AddDomainMatchingFunc(name string...
method rebuild (line 1237) | func (cdm *ConditionalDomainManager) rebuild() {
function NewConditionalDomainManager (line 1078) | func NewConditionalDomainManager(maxHierarchyLevel int) *ConditionalDoma...
FILE: rbac/default-role-manager/role_manager_test.go
function testRole (line 27) | func testRole(t *testing.T, rm rbac.RoleManager, name1 string, name2 str...
function testDomainRole (line 37) | func testDomainRole(t *testing.T, rm rbac.RoleManager, name1 string, nam...
function testPrintRoles (line 47) | func testPrintRoles(t *testing.T, rm rbac.RoleManager, name string, res ...
function testPrintUsers (line 57) | func testPrintUsers(t *testing.T, rm rbac.RoleManager, name string, res ...
function testPrintRolesWithDomain (line 67) | func testPrintRolesWithDomain(t *testing.T, rm rbac.RoleManager, name st...
function TestRole (line 76) | func TestRole(t *testing.T) {
function TestDomainRole (line 165) | func TestDomainRole(t *testing.T) {
function TestClear (line 232) | func TestClear(t *testing.T) {
function TestDomainPatternRole (line 267) | func TestDomainPatternRole(t *testing.T) {
function TestAllMatchingFunc (line 297) | func TestAllMatchingFunc(t *testing.T) {
function TestMatchingFuncOrder (line 311) | func TestMatchingFuncOrder(t *testing.T) {
function TestDomainMatchingFuncWithDifferentDomain (line 332) | func TestDomainMatchingFuncWithDifferentDomain(t *testing.T) {
function TestTemporaryRoles (line 343) | func TestTemporaryRoles(t *testing.T) {
function TestMaxHierarchyLevel (line 366) | func TestMaxHierarchyLevel(t *testing.T) {
function TestConcurrentHasLink (line 396) | func TestConcurrentHasLink(t *testing.T) {
FILE: rbac/role_manager.go
type MatchingFunc (line 17) | type MatchingFunc
type RoleManager (line 22) | type RoleManager interface
type ConditionalRoleManager (line 66) | type ConditionalRoleManager interface
FILE: rbac_api.go
method GetRolesForUser (line 29) | func (e *Enforcer) GetRolesForUser(name string, domain ...string) ([]str...
method GetUsersForRole (line 39) | func (e *Enforcer) GetUsersForRole(name string, domain ...string) ([]str...
method HasRoleForUser (line 49) | func (e *Enforcer) HasRoleForUser(name string, role string, domain ...st...
method AddRoleForUser (line 67) | func (e *Enforcer) AddRoleForUser(user string, role string, domain ...st...
method AddRolesForUser (line 75) | func (e *Enforcer) AddRolesForUser(user string, roles []string, domain ....
method DeleteRoleForUser (line 87) | func (e *Enforcer) DeleteRoleForUser(user string, role string, domain .....
method DeleteRolesForUser (line 95) | func (e *Enforcer) DeleteRolesForUser(user string, domain ...string) (bo...
method DeleteUser (line 109) | func (e *Enforcer) DeleteUser(user string) (bool, error) {
method DeleteRole (line 126) | func (e *Enforcer) DeleteRole(role string) (bool, error) {
method DeletePermission (line 148) | func (e *Enforcer) DeletePermission(permission ...string) (bool, error) {
method AddPermissionForUser (line 154) | func (e *Enforcer) AddPermissionForUser(user string, permission ...strin...
method AddPermissionsForUser (line 160) | func (e *Enforcer) AddPermissionsForUser(user string, permissions ...[]s...
method DeletePermissionForUser (line 170) | func (e *Enforcer) DeletePermissionForUser(user string, permission ...st...
method DeletePermissionsForUser (line 176) | func (e *Enforcer) DeletePermissionsForUser(user string) (bool, error) {
method GetPermissionsForUser (line 185) | func (e *Enforcer) GetPermissionsForUser(user string, domain ...string) ...
method GetNamedPermissionsForUser (line 190) | func (e *Enforcer) GetNamedPermissionsForUser(ptype string, user string,...
method HasPermissionForUser (line 221) | func (e *Enforcer) HasPermissionForUser(user string, permission ...strin...
method GetImplicitRolesForUser (line 233) | func (e *Enforcer) GetImplicitRolesForUser(name string, domain ...string...
method GetNamedImplicitRolesForUser (line 264) | func (e *Enforcer) GetNamedImplicitRolesForUser(ptype string, name strin...
method GetImplicitUsersForRole (line 275) | func (e *Enforcer) GetImplicitUsersForRole(name string, domain ...string...
method GetImplicitPermissionsForUser (line 307) | func (e *Enforcer) GetImplicitPermissionsForUser(user string, domain ......
method GetNamedImplicitPermissionsForUser (line 320) | func (e *Enforcer) GetNamedImplicitPermissionsForUser(ptype string, gtyp...
method GetImplicitUsersForPermission (line 373) | func (e *Enforcer) GetImplicitUsersForPermission(permission ...string) (...
method GetDomainsForUser (line 409) | func (e *Enforcer) GetDomainsForUser(user string) ([]string, error) {
method GetImplicitResourcesForUser (line 429) | func (e *Enforcer) GetImplicitResourcesForUser(user string, domain ...st...
function deepCopyPolicy (line 468) | func deepCopyPolicy(src []string) []string {
method GetAllowedObjectConditions (line 486) | func (e *Enforcer) GetAllowedObjectConditions(user string, action string...
function removeDuplicatePermissions (line 511) | func removeDuplicatePermissions(permissions [][]string) [][]string {
method GetImplicitUsersForResource (line 535) | func (e *Enforcer) GetImplicitUsersForResource(resource string) ([][]str...
method GetNamedImplicitUsersForResource (line 546) | func (e *Enforcer) GetNamedImplicitUsersForResource(ptype string, resour...
method GetImplicitUsersForResourceByDomain (line 603) | func (e *Enforcer) GetImplicitUsersForResourceByDomain(resource string, ...
method GetImplicitObjectPatternsForUser (line 663) | func (e *Enforcer) GetImplicitObjectPatternsForUser(user string, domain ...
method matchDomain (line 711) | func (e *Enforcer) matchDomain(domainIndex int, domain string, rule []st...
FILE: rbac_api_context.go
method AddRoleForUserCtx (line 28) | func (e *ContextEnforcer) AddRoleForUserCtx(ctx context.Context, user st...
method DeleteRoleForUserCtx (line 36) | func (e *ContextEnforcer) DeleteRoleForUserCtx(ctx context.Context, user...
method DeleteRolesForUserCtx (line 44) | func (e *ContextEnforcer) DeleteRolesForUserCtx(ctx context.Context, use...
method DeleteUserCtx (line 58) | func (e *ContextEnforcer) DeleteUserCtx(ctx context.Context, user string...
method DeleteRoleCtx (line 75) | func (e *ContextEnforcer) DeleteRoleCtx(ctx context.Context, role string...
method DeletePermissionCtx (line 97) | func (e *ContextEnforcer) DeletePermissionCtx(ctx context.Context, permi...
method AddPermissionForUserCtx (line 103) | func (e *ContextEnforcer) AddPermissionForUserCtx(ctx context.Context, u...
method AddPermissionsForUserCtx (line 109) | func (e *ContextEnforcer) AddPermissionsForUserCtx(ctx context.Context, ...
method DeletePermissionForUserCtx (line 119) | func (e *ContextEnforcer) DeletePermissionForUserCtx(ctx context.Context...
method DeletePermissionsForUserCtx (line 125) | func (e *ContextEnforcer) DeletePermissionsForUserCtx(ctx context.Contex...
FILE: rbac_api_synced.go
method GetRolesForUser (line 18) | func (e *SyncedEnforcer) GetRolesForUser(name string, domain ...string) ...
method GetUsersForRole (line 25) | func (e *SyncedEnforcer) GetUsersForRole(name string, domain ...string) ...
method HasRoleForUser (line 32) | func (e *SyncedEnforcer) HasRoleForUser(name string, role string, domain...
method AddRoleForUser (line 40) | func (e *SyncedEnforcer) AddRoleForUser(user string, role string, domain...
method AddRolesForUser (line 48) | func (e *SyncedEnforcer) AddRolesForUser(user string, roles []string, do...
method DeleteRoleForUser (line 56) | func (e *SyncedEnforcer) DeleteRoleForUser(user string, role string, dom...
method DeleteRolesForUser (line 64) | func (e *SyncedEnforcer) DeleteRolesForUser(user string, domain ...strin...
method DeleteUser (line 72) | func (e *SyncedEnforcer) DeleteUser(user string) (bool, error) {
method DeleteRole (line 80) | func (e *SyncedEnforcer) DeleteRole(role string) (bool, error) {
method DeletePermission (line 88) | func (e *SyncedEnforcer) DeletePermission(permission ...string) (bool, e...
method AddPermissionForUser (line 96) | func (e *SyncedEnforcer) AddPermissionForUser(user string, permission .....
method AddPermissionsForUser (line 104) | func (e *SyncedEnforcer) AddPermissionsForUser(user string, permissions ...
method DeletePermissionForUser (line 112) | func (e *SyncedEnforcer) DeletePermissionForUser(user string, permission...
method DeletePermissionsForUser (line 120) | func (e *SyncedEnforcer) DeletePermissionsForUser(user string) (bool, er...
method GetPermissionsForUser (line 127) | func (e *SyncedEnforcer) GetPermissionsForUser(user string, domain ...st...
method GetNamedPermissionsForUser (line 134) | func (e *SyncedEnforcer) GetNamedPermissionsForUser(ptype string, user s...
method HasPermissionForUser (line 141) | func (e *SyncedEnforcer) HasPermissionForUser(user string, permission .....
method GetImplicitRolesForUser (line 155) | func (e *SyncedEnforcer) GetImplicitRolesForUser(name string, domain ......
method GetImplicitPermissionsForUser (line 170) | func (e *SyncedEnforcer) GetImplicitPermissionsForUser(user string, doma...
method GetNamedImplicitPermissionsForUser (line 185) | func (e *SyncedEnforcer) GetNamedImplicitPermissionsForUser(ptype string...
method GetImplicitUsersForPermission (line 199) | func (e *SyncedEnforcer) GetImplicitUsersForPermission(permission ...str...
method GetImplicitObjectPatternsForUser (line 214) | func (e *SyncedEnforcer) GetImplicitObjectPatternsForUser(user string, d...
FILE: rbac_api_test.go
function testGetRoles (line 29) | func testGetRoles(t *testing.T, e *Enforcer, res []string, name string, ...
function testGetUsers (line 42) | func testGetUsers(t *testing.T, e *Enforcer, res []string, name string, ...
function testHasRole (line 60) | func testHasRole(t *testing.T, e *Enforcer, name string, role string, re...
function TestRoleAPI (line 73) | func TestRoleAPI(t *testing.T) {
function TestRoleAPI_Domains (line 132) | func TestRoleAPI_Domains(t *testing.T) {
function TestEnforcer_AddRolesForUser (line 178) | func TestEnforcer_AddRolesForUser(t *testing.T) {
function testGetPermissions (line 194) | func testGetPermissions(t *testing.T, e *Enforcer, name string, res [][]...
function testHasPermission (line 207) | func testHasPermission(t *testing.T, e *Enforcer, name string, permissio...
function testGetNamedPermissionsForUser (line 221) | func testGetNamedPermissionsForUser(t *testing.T, e *Enforcer, ptype str...
function TestPermissionAPI (line 234) | func TestPermissionAPI(t *testing.T) {
function testGetImplicitRoles (line 290) | func testGetImplicitRoles(t *testing.T, e *Enforcer, name string, res []...
function testGetImplicitRolesInDomain (line 300) | func testGetImplicitRolesInDomain(t *testing.T, e *Enforcer, name string...
function TestImplicitRoleAPI (line 310) | func TestImplicitRoleAPI(t *testing.T) {
function testGetImplicitPermissions (line 329) | func testGetImplicitPermissions(t *testing.T, e *Enforcer, name string, ...
function testGetImplicitPermissionsWithDomain (line 339) | func testGetImplicitPermissionsWithDomain(t *testing.T, e *Enforcer, nam...
function testGetNamedImplicitPermissions (line 349) | func testGetNamedImplicitPermissions(t *testing.T, e *Enforcer, ptype st...
function TestImplicitPermissionAPI (line 359) | func TestImplicitPermissionAPI(t *testing.T) {
function TestImplicitPermissionAPIWithDomain (line 391) | func TestImplicitPermissionAPIWithDomain(t *testing.T) {
function testGetImplicitUsers (line 396) | func testGetImplicitUsers(t *testing.T, e *Enforcer, res []string, permi...
function TestImplicitUserAPI (line 409) | func TestImplicitUserAPI(t *testing.T) {
function testGetImplicitResourcesForUser (line 424) | func testGetImplicitResourcesForUser(t *testing.T, e *Enforcer, res [][]...
function TestGetImplicitResourcesForUser (line 450) | func TestGetImplicitResourcesForUser(t *testing.T) {
function TestImplicitUsersForRole (line 472) | func TestImplicitUsersForRole(t *testing.T) {
function testGetImplicitUsersForRole (line 482) | func testGetImplicitUsersForRole(t *testing.T, e *Enforcer, name string,...
function TestExplicitPriorityModify (line 494) | func TestExplicitPriorityModify(t *testing.T) {
function TestCustomizedFieldIndex (line 517) | func TestCustomizedFieldIndex(t *testing.T) {
function testGetAllowedObjectConditions (line 560) | func testGetAllowedObjectConditions(t *testing.T, e *Enforcer, user stri...
function TestGetAllowedObjectConditions (line 574) | func TestGetAllowedObjectConditions(t *testing.T) {
function testGetImplicitUsersForResource (line 609) | func testGetImplicitUsersForResource(t *testing.T, e *Enforcer, res [][]...
function TestGetImplicitUsersForResource (line 623) | func TestGetImplicitUsersForResource(t *testing.T) {
function TestGetImplicitUsersForResourceWithResourceRoles (line 638) | func TestGetImplicitUsersForResourceWithResourceRoles(t *testing.T) {
function testGetImplicitUsersForResourceByDomain (line 675) | func testGetImplicitUsersForResourceByDomain(t *testing.T, e *Enforcer, ...
function TestGetImplicitUsersForResourceByDomain (line 689) | func TestGetImplicitUsersForResourceByDomain(t *testing.T) {
function TestConditional (line 700) | func TestConditional(t *testing.T) {
function TestMaxHierarchyLevelConsistency (line 715) | func TestMaxHierarchyLevelConsistency(t *testing.T) {
function testGetImplicitObjectPatternsForUser (line 848) | func testGetImplicitObjectPatternsForUser(t *testing.T, e *Enforcer, use...
function TestGetImplicitObjectPatternsForUser (line 861) | func TestGetImplicitObjectPatternsForUser(t *testing.T) {
FILE: rbac_api_with_domains.go
method GetUsersForRoleInDomain (line 24) | func (e *Enforcer) GetUsersForRoleInDomain(name string, domain string) [...
method GetRolesForUserInDomain (line 33) | func (e *Enforcer) GetRolesForUserInDomain(name string, domain string) [...
method GetPermissionsForUserInDomain (line 42) | func (e *Enforcer) GetPermissionsForUserInDomain(user string, domain str...
method AddRoleForUserInDomain (line 49) | func (e *Enforcer) AddRoleForUserInDomain(user string, role string, doma...
method DeleteRoleForUserInDomain (line 55) | func (e *Enforcer) DeleteRoleForUserInDomain(user string, role string, d...
method DeleteRolesForUserInDomain (line 61) | func (e *Enforcer) DeleteRolesForUserInDomain(user string, domain string...
method GetAllUsersByDomain (line 79) | func (e *Enforcer) GetAllUsersByDomain(domain string) ([]string, error) {
method DeleteAllUsersByDomain (line 112) | func (e *Enforcer) DeleteAllUsersByDomain(domain string) (bool, error) {
method DeleteDomains (line 149) | func (e *Enforcer) DeleteDomains(domains ...string) (bool, error) {
method GetAllDomains (line 172) | func (e *Enforcer) GetAllDomains() ([]string, error) {
method GetAllRolesByDomain (line 181) | func (e *Enforcer) GetAllRolesByDomain(domain string) ([]string, error) {
FILE: rbac_api_with_domains_context.go
method AddRoleForUserInDomainCtx (line 26) | func (e *ContextEnforcer) AddRoleForUserInDomainCtx(ctx context.Context,...
method DeleteRoleForUserInDomainCtx (line 32) | func (e *ContextEnforcer) DeleteRoleForUserInDomainCtx(ctx context.Conte...
method DeleteRolesForUserInDomainCtx (line 38) | func (e *ContextEnforcer) DeleteRolesForUserInDomainCtx(ctx context.Cont...
method DeleteAllUsersByDomainCtx (line 56) | func (e *ContextEnforcer) DeleteAllUsersByDomainCtx(ctx context.Context,...
method DeleteDomainsCtx (line 93) | func (e *ContextEnforcer) DeleteDomainsCtx(ctx context.Context, domains ...
FILE: rbac_api_with_domains_synced.go
method GetUsersForRoleInDomain (line 18) | func (e *SyncedEnforcer) GetUsersForRoleInDomain(name string, domain str...
method GetRolesForUserInDomain (line 25) | func (e *SyncedEnforcer) GetRolesForUserInDomain(name string, domain str...
method GetPermissionsForUserInDomain (line 32) | func (e *SyncedEnforcer) GetPermissionsForUserInDomain(user string, doma...
method AddRoleForUserInDomain (line 40) | func (e *SyncedEnforcer) AddRoleForUserInDomain(user string, role string...
method DeleteRoleForUserInDomain (line 48) | func (e *SyncedEnforcer) DeleteRoleForUserInDomain(user string, role str...
method DeleteRolesForUserInDomain (line 56) | func (e *SyncedEnforcer) DeleteRolesForUserInDomain(user string, domain ...
method DeleteDomains (line 64) | func (e *SyncedEnforcer) DeleteDomains(domains ...string) (bool, error) {
FILE: rbac_api_with_domains_test.go
function testGetUsersInDomain (line 25) | func testGetUsersInDomain(t *testing.T, e *Enforcer, name string, domain...
function testGetRolesInDomain (line 35) | func testGetRolesInDomain(t *testing.T, e *Enforcer, name string, domain...
function TestGetImplicitRolesForDomainUser (line 45) | func TestGetImplicitRolesForDomainUser(t *testing.T) {
function TestUserAPIWithDomains (line 56) | func TestUserAPIWithDomains(t *testing.T) {
function TestRoleAPIWithDomains (line 87) | func TestRoleAPIWithDomains(t *testing.T) {
function testGetPermissionsInDomain (line 169) | func testGetPermissionsInDomain(t *testing.T, e *Enforcer, name string, ...
function TestPermissionAPIInDomain (line 179) | func TestPermissionAPIInDomain(t *testing.T) {
function testGetDomainsForUser (line 193) | func testGetDomainsForUser(t *testing.T, e *Enforcer, res []string, user...
function TestGetDomainsForUser (line 205) | func TestGetDomainsForUser(t *testing.T) {
function testGetAllUsersByDomain (line 213) | func testGetAllUsersByDomain(t *testing.T, e *Enforcer, domain string, e...
function TestGetAllUsersByDomain (line 220) | func TestGetAllUsersByDomain(t *testing.T) {
function testDeleteAllUsersByDomain (line 227) | func testDeleteAllUsersByDomain(t *testing.T, domain string, expectedPol...
function TestDeleteAllUsersByDomain (line 248) | func TestDeleteAllUsersByDomain(t *testing.T) {
function testGetAllDomains (line 264) | func testGetAllDomains(t *testing.T, e *Enforcer, res []string) {
function TestGetAllDomains (line 274) | func TestGetAllDomains(t *testing.T) {
function testGetAllRolesByDomain (line 280) | func testGetAllRolesByDomain(t *testing.T, e *Enforcer, domain string, e...
function TestGetAllRolesByDomain (line 287) | func TestGetAllRolesByDomain(t *testing.T) {
function testDeleteDomains (line 300) | func testDeleteDomains(t *testing.T, domains []string, expectedPolicy, e...
function TestDeleteDomains (line 326) | func TestDeleteDomains(t *testing.T) {
function TestGetRolesForUserInDomainWithConditionalFunctions (line 345) | func TestGetRolesForUserInDomainWithConditionalFunctions(t *testing.T) {
FILE: role_manager_b_test.go
function BenchmarkRoleManagerSmall (line 10) | func BenchmarkRoleManagerSmall(b *testing.B) {
function BenchmarkRoleManagerMedium (line 47) | func BenchmarkRoleManagerMedium(b *testing.B) {
function BenchmarkRoleManagerLarge (line 88) | func BenchmarkRoleManagerLarge(b *testing.B) {
function BenchmarkBuildRoleLinksWithPatternLarge (line 123) | func BenchmarkBuildRoleLinksWithPatternLarge(b *testing.B) {
function BenchmarkBuildRoleLinksWithDomainPatternLarge (line 132) | func BenchmarkBuildRoleLinksWithDomainPatternLarge(b *testing.B) {
function BenchmarkBuildRoleLinksWithPatternAndDomainPatternLarge (line 141) | func BenchmarkBuildRoleLinksWithPatternAndDomainPatternLarge(b *testing....
function BenchmarkHasLinkWithPatternLarge (line 151) | func BenchmarkHasLinkWithPatternLarge(b *testing.B) {
function BenchmarkHasLinkWithDomainPatternLarge (line 161) | func BenchmarkHasLinkWithDomainPatternLarge(b *testing.B) {
function BenchmarkHasLinkWithPatternAndDomainPatternLarge (line 171) | func BenchmarkHasLinkWithPatternAndDomainPatternLarge(b *testing.B) {
function BenchmarkConcurrentHasLinkWithMatching (line 184) | func BenchmarkConcurrentHasLinkWithMatching(b *testing.B) {
FILE: syntax_test.go
function TestSyntaxMatcher (line 25) | func TestSyntaxMatcher(t *testing.T) {
FILE: transaction.go
constant defaultLockTimeout (line 29) | defaultLockTimeout = 30 * time.Second
type Transaction (line 35) | type Transaction struct
method AddPolicy (line 50) | func (tx *Transaction) AddPolicy(params ...interface{}) (bool, error) {
method buildRuleFromParams (line 55) | func (tx *Transaction) buildRuleFromParams(params ...interface{}) []st...
method checkTransactionStatus (line 72) | func (tx *Transaction) checkTransactionStatus() error {
method AddNamedPolicy (line 81) | func (tx *Transaction) AddNamedPolicy(ptype string, params ...interfac...
method AddPolicies (line 115) | func (tx *Transaction) AddPolicies(rules [][]string) (bool, error) {
method AddNamedPolicies (line 120) | func (tx *Transaction) AddNamedPolicies(ptype string, rules [][]string...
method RemovePolicy (line 166) | func (tx *Transaction) RemovePolicy(params ...interface{}) (bool, erro...
method RemoveNamedPolicy (line 171) | func (tx *Transaction) RemoveNamedPolicy(ptype string, params ...inter...
method RemovePolicies (line 205) | func (tx *Transaction) RemovePolicies(rules [][]string) (bool, error) {
method RemoveNamedPolicies (line 210) | func (tx *Transaction) RemoveNamedPolicies(ptype string, rules [][]str...
method UpdatePolicy (line 256) | func (tx *Transaction) UpdatePolicy(oldPolicy []string, newPolicy []st...
method UpdateNamedPolicy (line 261) | func (tx *Transaction) UpdateNamedPolicy(ptype string, oldPolicy []str...
method AddGroupingPolicy (line 305) | func (tx *Transaction) AddGroupingPolicy(params ...interface{}) (bool,...
method AddNamedGroupingPolicy (line 310) | func (tx *Transaction) AddNamedGroupingPolicy(ptype string, params ......
method RemoveGroupingPolicy (line 344) | func (tx *Transaction) RemoveGroupingPolicy(params ...interface{}) (bo...
method RemoveNamedGroupingPolicy (line 349) | func (tx *Transaction) RemoveNamedGroupingPolicy(ptype string, params ...
method GetBufferedModel (line 384) | func (tx *Transaction) GetBufferedModel() (model.Model, error) {
method HasOperations (line 396) | func (tx *Transaction) HasOperations() bool {
method OperationCount (line 403) | func (tx *Transaction) OperationCount() int {
function tryLockWithTimeout (line 410) | func tryLockWithTimeout(lock *sync.Mutex, startTime time.Time, maxWait t...
FILE: transaction_buffer.go
type TransactionBuffer (line 27) | type TransactionBuffer struct
method AddOperation (line 44) | func (tb *TransactionBuffer) AddOperation(op persist.PolicyOperation) {
method GetOperations (line 52) | func (tb *TransactionBuffer) GetOperations() []persist.PolicyOperation {
method Clear (line 64) | func (tb *TransactionBuffer) Clear() {
method GetModelSnapshot (line 72) | func (tb *TransactionBuffer) GetModelSnapshot() model.Model {
method ApplyOperationsToModel (line 81) | func (tb *TransactionBuffer) ApplyOperationsToModel(baseModel model.Mo...
method HasOperations (line 120) | func (tb *TransactionBuffer) HasOperations() bool {
method OperationCount (line 127) | func (tb *TransactionBuffer) OperationCount() int {
function NewTransactionBuffer (line 35) | func NewTransactionBuffer(baseModel model.Model) *TransactionBuffer {
FILE: transaction_commit.go
method Commit (line 27) | func (tx *Transaction) Commit() error {
method Rollback (line 105) | func (tx *Transaction) Rollback() error {
method applyOperationsToDatabase (line 135) | func (tx *Transaction) applyOperationsToDatabase() error {
method applyAddOperationToDatabase (line 160) | func (tx *Transaction) applyAddOperationToDatabase(adapter persist.Adapt...
method applyRemoveOperationToDatabase (line 176) | func (tx *Transaction) applyRemoveOperationToDatabase(adapter persist.Ad...
method applyUpdateOperationToDatabase (line 192) | func (tx *Transaction) applyUpdateOperationToDatabase(adapter persist.Ad...
method applyOperationsToModel (line 211) | func (tx *Transaction) applyOperationsToModel() error {
method IsCommitted (line 246) | func (tx *Transaction) IsCommitted() bool {
method IsRolledBack (line 253) | func (tx *Transaction) IsRolledBack() bool {
method IsActive (line 260) | func (tx *Transaction) IsActive() bool {
FILE: transaction_conflict.go
type ConflictError (line 25) | type ConflictError struct
method Error (line 30) | func (e *ConflictError) Error() string {
type ConflictDetector (line 35) | type ConflictDetector struct
method DetectConflicts (line 52) | func (cd *ConflictDetector) DetectConflicts() error {
method detectRemoveConflict (line 75) | func (cd *ConflictDetector) detectRemoveConflict(op persist.PolicyOper...
method detectUpdateConflict (line 102) | func (cd *ConflictDetector) detectUpdateConflict(op persist.PolicyOper...
function NewConflictDetector (line 42) | func NewConflictDetector(baseModel, currentModel model.Model, operations...
FILE: transaction_test.go
type MockTransactionalAdapter (line 27) | type MockTransactionalAdapter struct
method LoadPolicy (line 44) | func (a *MockTransactionalAdapter) LoadPolicy(model model.Model) error {
method SavePolicy (line 49) | func (a *MockTransactionalAdapter) SavePolicy(model model.Model) error {
method AddPolicy (line 54) | func (a *MockTransactionalAdapter) AddPolicy(sec string, ptype string,...
method RemovePolicy (line 59) | func (a *MockTransactionalAdapter) RemovePolicy(sec string, ptype stri...
method RemoveFilteredPolicy (line 64) | func (a *MockTransactionalAdapter) RemoveFilteredPolicy(sec string, pt...
method BeginTransaction (line 69) | func (a *MockTransactionalAdapter) BeginTransaction(ctx context.Contex...
type MockTransactionContext (line 32) | type MockTransactionContext struct
method Commit (line 74) | func (tx *MockTransactionContext) Commit() error {
method Rollback (line 83) | func (tx *MockTransactionContext) Rollback() error {
method GetAdapter (line 92) | func (tx *MockTransactionContext) GetAdapter() persist.Adapter {
function NewMockTransactionalAdapter (line 39) | func NewMockTransactionalAdapter() *MockTransactionalAdapter {
function TestTransactionBasicOperations (line 97) | func TestTransactionBasicOperations(t *testing.T) {
function TestTransactionRollback (line 136) | func TestTransactionRollback(t *testing.T) {
function TestConcurrentTransactions (line 170) | func TestConcurrentTransactions(t *testing.T) {
function TestTransactionConflicts (line 224) | func TestTransactionConflicts(t *testing.T) {
function TestTransactionBuffer (line 288) | func TestTransactionBuffer(t *testing.T) {
FILE: util/builtin_operators.go
function mustCompileOrGet (line 44) | func mustCompileOrGet(key string) *regexp.Regexp {
function validateVariadicArgs (line 60) | func validateVariadicArgs(expectedLen int, args ...interface{}) error {
function validateVariadicStringArgs (line 76) | func validateVariadicStringArgs(expectedLen int, args ...string) error {
function KeyMatch (line 85) | func KeyMatch(key1 string, key2 string) bool {
function KeyMatchFunc (line 98) | func KeyMatchFunc(args ...interface{}) (interface{}, error) {
function KeyGet (line 112) | func KeyGet(key1, key2 string) string {
function KeyGetFunc (line 126) | func KeyGetFunc(args ...interface{}) (interface{}, error) {
function KeyMatch2 (line 139) | func KeyMatch2(key1 string, key2 string) bool {
function KeyMatch2Func (line 148) | func KeyMatch2Func(args ...interface{}) (interface{}, error) {
function KeyGet2 (line 162) | func KeyGet2(key1, key2 string, pathVar string) string {
function KeyGet2Func (line 182) | func KeyGet2Func(args ...interface{}) (interface{}, error) {
function KeyMatch3 (line 196) | func KeyMatch3(key1 string, key2 string) bool {
function KeyMatch3Func (line 204) | func KeyMatch3Func(args ...interface{}) (interface{}, error) {
function KeyGet3 (line 218) | func KeyGet3(key1, key2 string, pathVar string) string {
function KeyGet3Func (line 238) | func KeyGet3Func(args ...interface{}) (interface{}, error) {
function KeyMatch4 (line 255) | func KeyMatch4(key1 string, key2 string) bool {
function KeyMatch4Func (line 292) | func KeyMatch4Func(args ...interface{}) (interface{}, error) {
function KeyMatch5 (line 308) | func KeyMatch5(key1 string, key2 string) bool {
function KeyMatch5Func (line 322) | func KeyMatch5Func(args ...interface{}) (interface{}, error) {
function RegexMatch (line 334) | func RegexMatch(key1 string, key2 string) bool {
function RegexMatchFunc (line 343) | func RegexMatchFunc(args ...interface{}) (interface{}, error) {
function IPMatch (line 356) | func IPMatch(ip1 string, ip2 string) bool {
function IPMatchFunc (line 376) | func IPMatchFunc(args ...interface{}) (interface{}, error) {
function GlobMatch (line 388) | func GlobMatch(key1 string, key2 string) (bool, error) {
function GlobMatchFunc (line 393) | func GlobMatchFunc(args ...interface{}) (interface{}, error) {
function GenerateGFunction (line 405) | func GenerateGFunction(rm rbac.RoleManager) govaluate.ExpressionFunction {
function GenerateConditionalGFunction (line 448) | func GenerateConditionalGFunction(crm rbac.ConditionalRoleManager) goval...
function TimeMatchFunc (line 470) | func TimeMatchFunc(args ...string) (bool, error) {
function TimeMatch (line 479) | func TimeMatch(startTime, endTime string) (bool, error) {
FILE: util/builtin_operators_test.go
function testKeyMatch (line 21) | func testKeyMatch(t *testing.T, key1 string, key2 string, res bool) {
function TestKeyMatch (line 31) | func TestKeyMatch(t *testing.T) {
function testKeyGet (line 43) | func testKeyGet(t *testing.T, key1 string, key2 string, res string) {
function TestKeyGet (line 53) | func TestKeyGet(t *testing.T) {
function testKeyMatch2 (line 65) | func testKeyMatch2(t *testing.T, key1 string, key2 string, res bool) {
function testGlobMatch (line 75) | func testGlobMatch(t *testing.T, key1 string, key2 string, res bool) {
function TestKeyMatch2 (line 88) | func TestKeyMatch2(t *testing.T) {
function testKeyGet2 (line 119) | func testKeyGet2(t *testing.T, key1 string, key2 string, pathVar string,...
function TestKeyGet2 (line 129) | func TestKeyGet2(t *testing.T) {
function testKeyMatch3 (line 162) | func testKeyMatch3(t *testing.T, key1 string, key2 string, res bool) {
function TestKeyMatch3 (line 172) | func TestKeyMatch3(t *testing.T) {
function testKeyGet3 (line 199) | func testKeyGet3(t *testing.T, key1 string, key2 string, pathVar string,...
function TestKeyGet3 (line 209) | func TestKeyGet3(t *testing.T) {
function testKeyMatch4 (line 249) | func testKeyMatch4(t *testing.T, key1 string, key2 string, res bool) {
function TestKeyMatch4 (line 259) | func TestKeyMatch4(t *testing.T) {
function testRegexMatch (line 275) | func testRegexMatch(t *testing.T, key1 string, key2 string, res bool) {
function TestRegexMatch (line 285) | func TestRegexMatch(t *testing.T) {
function testIPMatch (line 297) | func testIPMatch(t *testing.T, ip1 string, ip2 string, res bool) {
function TestIPMatch (line 307) | func TestIPMatch(t *testing.T) {
function testRegexMatchFunc (line 317) | func testRegexMatchFunc(t *testing.T, res bool, err string, args ...inte...
function testKeyMatchFunc (line 331) | func testKeyMatchFunc(t *testing.T, res bool, err string, args ...interf...
function testKeyMatch2Func (line 345) | func testKeyMatch2Func(t *testing.T, res bool, err string, args ...inter...
function testKeyMatch3Func (line 359) | func testKeyMatch3Func(t *testing.T, res bool, err string, args ...inter...
function testKeyMatch4Func (line 373) | func testKeyMatch4Func(t *testing.T, res bool, err string, args ...inter...
function testKeyMatch5Func (line 387) | func testKeyMatch5Func(t *testing.T, res bool, err string, args ...inter...
function testIPMatchFunc (line 401) | func testIPMatchFunc(t *testing.T, res bool, err string, args ...interfa...
function TestRegexMatchFunc (line 415) | func TestRegexMatchFunc(t *testing.T) {
function TestKeyMatchFunc (line 422) | func TestKeyMatchFunc(t *testing.T) {
function TestKeyMatch2Func (line 431) | func TestKeyMatch2Func(t *testing.T) {
function TestKeyMatch3Func (line 444) | func TestKeyMatch3Func(t *testing.T) {
function TestKeyMatch4Func (line 472) | func TestKeyMatch4Func(t *testing.T) {
function TestKeyMatch5Func (line 484) | func TestKeyMatch5Func(t *testing.T) {
function TestIPMatchFunc (line 526) | func TestIPMatchFunc(t *testing.T) {
function TestGlobMatch (line 532) | func TestGlobMatch(t *testing.T) {
function testTimeMatch (line 643) | func testTimeMatch(t *testing.T, startTime string, endTime string, res b...
function TestTestMatch (line 656) | func TestTestMatch(t *testing.T) {
FILE: util/util.go
function JsonToMap (line 29) | func JsonToMap(jsonStr string) (map[string]interface{}, error) {
function EscapeAssertion (line 39) | func EscapeAssertion(s string) string {
function RemoveComments (line 52) | func RemoveComments(s string) string {
function ArrayEquals (line 61) | func ArrayEquals(a []string, b []string) bool {
function Array2DEquals (line 75) | func Array2DEquals(a [][]string, b [][]string) bool {
function SortArray2D (line 89) | func SortArray2D(arr [][]string) {
function SortedArray2DEquals (line 108) | func SortedArray2DEquals(a [][]string, b [][]string) bool {
function ArrayRemoveDuplicates (line 129) | func ArrayRemoveDuplicates(s *[]string) {
function ArrayToString (line 143) | func ArrayToString(s []string) string {
function ParamsToString (line 148) | func ParamsToString(s ...string) string {
function SetEquals (line 153) | func SetEquals(a []string, b []string) bool {
function SetEqualsInt (line 170) | func SetEqualsInt(a []int, b []int) bool {
function Set2DEquals (line 187) | func Set2DEquals(a [][]string, b [][]string) bool {
function JoinSlice (line 207) | func JoinSlice(a string, b ...string) []string {
function JoinSliceAny (line 217) | func JoinSliceAny(a string, b ...string) []interface{} {
function SetSubtract (line 229) | func SetSubtract(a []string, b []string) []string {
function HasEval (line 244) | func HasEval(s string) bool {
function ReplaceEval (line 249) | func ReplaceEval(s string, rule string) string {
function ReplaceEvalWithMap (line 254) | func ReplaceEvalWithMap(src string, sets map[string]string) string {
function GetEvalValue (line 270) | func GetEvalValue(s string) []string {
function EscapeStringLiterals (line 283) | func EscapeStringLiterals(expr string) string {
function RemoveDuplicateElement (line 314) | func RemoveDuplicateElement(s []string) []string {
type node (line 326) | type node struct
type LRUCache (line 333) | type LRUCache struct
method remove (line 357) | func (cache *LRUCache) remove(n *node, listOnly bool) {
method add (line 365) | func (cache *LRUCache) add(n *node, listOnly bool) {
method moveToHead (line 376) | func (cache *LRUCache) moveToHead(n *node) {
method Get (line 381) | func (cache *LRUCache) Get(key interface{}) (value interface{}, ok boo...
method Put (line 391) | func (cache *LRUCache) Put(key interface{}, value interface{}) {
function NewLRUCache (line 340) | func NewLRUCache(capacity int) *LRUCache {
type SyncLRUCache (line 404) | type SyncLRUCache struct
method Get (line 415) | func (cache *SyncLRUCache) Get(key interface{}) (value interface{}, ok...
method Put (line 421) | func (cache *SyncLRUCache) Put(key interface{}, value interface{}) {
function NewSyncLRUCache (line 409) | func NewSyncLRUCache(capacity int) *SyncLRUCache {
FILE: util/util_test.go
function testEscapeAssertion (line 21) | func testEscapeAssertion(t *testing.T, s string, res string) {
function TestEscapeAssertion (line 31) | func TestEscapeAssertion(t *testing.T) {
function testRemoveComments (line 55) | func testRemoveComments(t *testing.T, s string, res string) {
function TestRemoveComments (line 65) | func TestRemoveComments(t *testing.T) {
function testArrayEquals (line 73) | func testArrayEquals(t *testing.T, a []string, b []string, res bool) {
function TestArrayEquals (line 83) | func TestArrayEquals(t *testing.T) {
function testArray2DEquals (line 90) | func testArray2DEquals(t *testing.T, a [][]string, b [][]string, res boo...
function TestArray2DEquals (line 100) | func TestArray2DEquals(t *testing.T) {
function testSetEquals (line 108) | func testSetEquals(t *testing.T, a []string, b []string, res bool) {
function TestSetEquals (line 118) | func TestSetEquals(t *testing.T) {
function testContainEval (line 125) | func testContainEval(t *testing.T, s string, res bool) {
function TestContainEval (line 132) | func TestContainEval(t *testing.T) {
function testReplaceEval (line 140) | func testReplaceEval(t *testing.T, s string, rule string, res string) {
function TestReplaceEval (line 148) | func TestReplaceEval(t *testing.T) {
function testGetEvalValue (line 153) | func testGetEvalValue(t *testing.T, s string, res []string) {
function TestGetEvalValue (line 162) | func TestGetEvalValue(t *testing.T) {
function testReplaceEvalWithMap (line 169) | func testReplaceEvalWithMap(t *testing.T, s string, sets map[string]stri...
function TestReplaceEvalWithMap (line 178) | func TestReplaceEvalWithMap(t *testing.T) {
function testCacheGet (line 193) | func testCacheGet(t *testing.T, c *LRUCache, key string, value interface...
function testCachePut (line 200) | func testCachePut(t *testing.T, c *LRUCache, key string, value interface...
function testCacheEqual (line 208) | func testCacheEqual(t *testing.T, c *LRUCache, values []int) {
function TestLRUCache (line 219) | func TestLRUCache(t *testing.T) {
function testEscapeStringLiterals (line 230) | func testEscapeStringLiterals(t *testing.T, input string, expected strin...
function TestEscapeStringLiterals (line 242) | func TestEscapeStringLiterals(t *testing.T) {
FILE: util_log.go
method onLogBeforeEvent (line 23) | func (e *Enforcer) onLogBeforeEvent(eventType log.EventType) *log.LogEnt...
method onLogAfterEvent (line 35) | func (e *Enforcer) onLogAfterEvent(logEntry *log.LogEntry) {
method onLogAfterEventWithError (line 42) | func (e *Enforcer) onLogAfterEventWithError(logEntry *log.LogEntry, err ...
function countModelRules (line 50) | func countModelRules(m model.Model) int {
method onLogBeforeEventInLoadPolicy (line 66) | func (e *Enforcer) onLogBeforeEventInLoadPolicy() *log.LogEntry {
method onLogAfterEventInLoadPolicy (line 71) | func (e *Enforcer) onLogAfterEventInLoadPolicy(logEntry *log.LogEntry, n...
method onLogBeforeEventInSavePolicy (line 79) | func (e *Enforcer) onLogBeforeEventInSavePolicy() *log.LogEntry {
method onLogAfterEventInSavePolicy (line 92) | func (e *Enforcer) onLogAfterEventInSavePolicy(logEntry *log.LogEntry) {
method createEnforceLogEntry (line 97) | func (e *Enforcer) createEnforceLogEntry(rvals []interface{}) *log.LogEn...
method onLogBeforeEventInEnforce (line 125) | func (e *Enforcer) onLogBeforeEventInEnforce(rvals []interface{}) *log.L...
method onLogAfterEventInEnforce (line 135) | func (e *Enforcer) onLogAfterEventInEnforce(logEntry *log.LogEntry, allo...
method logPolicyOperation (line 143) | func (e *Enforcer) logPolicyOperation(eventType log.EventType, sec strin...
FILE: watcher_ex_test.go
type SampleWatcherEx (line 23) | type SampleWatcherEx struct
method UpdateForAddPolicy (line 27) | func (w SampleWatcherEx) UpdateForAddPolicy(sec, ptype string, params ...
method UpdateForRemovePolicy (line 30) | func (w SampleWatcherEx) UpdateForRemovePolicy(sec, ptype string, para...
method UpdateForRemoveFilteredPolicy (line 34) | func (w SampleWatcherEx) UpdateForRemoveFilteredPolicy(sec, ptype stri...
method UpdateForSavePolicy (line 38) | func (w SampleWatcherEx) UpdateForSavePolicy(model model.Model) error {
method UpdateForAddPolicies (line 42) | func (w SampleWatcherEx) UpdateForAddPolicies(sec string, ptype string...
method UpdateForRemovePolicies (line 46) | func (w SampleWatcherEx) UpdateForRemovePolicies(sec string, ptype str...
function TestSetWatcherEx (line 50) | func TestSetWatcherEx(t *testing.T) {
FILE: watcher_test.go
type SampleWatcher (line 19) | type SampleWatcher struct
method Close (line 23) | func (w *SampleWatcher) Close() {
method SetUpdateCallback (line 26) | func (w *SampleWatcher) SetUpdateCallback(callback func(string)) error {
method Update (line 31) | func (w *SampleWatcher) Update() error {
function TestSetWatcher (line 38) | func TestSetWatcher(t *testing.T) {
function TestSelfModify (line 54) | func TestSelfModify(t *testing.T) {
FILE: watcher_update_test.go
type SampleWatcherUpdatable (line 21) | type SampleWatcherUpdatable struct
method UpdateForUpdatePolicy (line 25) | func (w SampleWatcherUpdatable) UpdateForUpdatePolicy(params ...string...
function TestSetWatcherUpdatable (line 29) | func TestSetWatcherUpdatable(t *testing.T) {
Condensed preview — 225 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,130K chars).
[
{
"path": ".asf.yaml",
"chars": 1169,
"preview": "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements. See the NOTICE f"
},
{
"path": ".github/scripts/benchmark_formatter.py",
"chars": 8967,
"preview": "import pathlib, re, sys\n\ntry:\n p = pathlib.Path(\"comparison.md\")\n if not p.exists():\n print(\"comparison.md "
},
{
"path": ".github/scripts/download_artifact.js",
"chars": 1020,
"preview": "module.exports = async ({github, context, core}) => {\n try {\n const artifacts = await github.rest.actions.listWorkfl"
},
{
"path": ".github/scripts/post_comment.js",
"chars": 1814,
"preview": "module.exports = async ({github, context, core}) => {\n const fs = require('fs');\n \n // Validate pr_number.txt\n if (!"
},
{
"path": ".github/semantic.yml",
"chars": 72,
"preview": "# Always validate the PR title AND all the commits\ntitleAndCommits: true"
},
{
"path": ".github/workflows/comment.yml",
"chars": 952,
"preview": "name: Post Benchmark Comment\n\non:\n workflow_run:\n workflows: [\"Performance Comparison for Pull Requests\"]\n types:"
},
{
"path": ".github/workflows/default.yml",
"chars": 1161,
"preview": "name: Build\n\non:\n push:\n branches:\n - master\n pull_request:\n\njobs:\n test:\n runs-on: ubuntu-latest\n stra"
},
{
"path": ".github/workflows/golangci-lint.yml",
"chars": 400,
"preview": "name: golangci-lint\n\non:\n push:\n branches:\n - master\n - main\n pull_request:\n\njobs:\n golangci:\n runs-o"
},
{
"path": ".github/workflows/performance-pr.yml",
"chars": 2872,
"preview": "name: Performance Comparison for Pull Requests\n\non:\n pull_request:\n branches: [master]\n\njobs:\n benchmark-pr:\n na"
},
{
"path": ".gitignore",
"chars": 303,
"preview": "# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.o\n*.a\n*.so\n\n# Folders\n_obj\n_test\n\n# Architecture spe"
},
{
"path": ".golangci.yml",
"chars": 16842,
"preview": "# Based on https://gist.github.com/maratori/47a4d00457a92aa426dbd48a18776322\n# This code is licensed under the terms of "
},
{
"path": ".releaserc.json",
"chars": 289,
"preview": "{\n \"debug\": true,\n \"branches\": [\n \"+([0-9])?(.{+([0-9]),x}).x\",\n \"master\",\n {\n \"name\": \"beta\",\n \"pr"
},
{
"path": "CONTRIBUTING.md",
"chars": 2325,
"preview": "# How to contribute\n\nThe following is a set of guidelines for contributing to casbin and its libraries, which are hosted"
},
{
"path": "DISCLAIMER",
"chars": 551,
"preview": "Apache Casbin(Incubating) is an effort undergoing incubation at the Apache Software Foundation (ASF), sponsored by the A"
},
{
"path": "LICENSE",
"chars": 11357,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "Makefile",
"chars": 223,
"preview": "SHELL = /bin/bash\nexport PATH := $(shell yarn global bin):$(PATH)\n\ndefault: lint test\n\ntest:\n\tgo test -race -v ./...\n\nbe"
},
{
"path": "README.md",
"chars": 15953,
"preview": "Casbin\n====\n\n[](https://goreportcard.com/repor"
},
{
"path": "abac_test.go",
"chars": 6447,
"preview": "// Copyright 2025 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "ai_api.go",
"chars": 6299,
"preview": "// Copyright 2026 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "ai_api_test.go",
"chars": 7075,
"preview": "// Copyright 2026 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "biba_test.go",
"chars": 1755,
"preview": "// Copyright 2025 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "blp_test.go",
"chars": 1949,
"preview": "// Copyright 2025 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "config/config.go",
"chars": 6646,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "config/config_test.go",
"chars": 3977,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "config/testdata/testini.ini",
"chars": 654,
"preview": "# test config\ndebug = true\nurl = act.wiki\n\n; redis config\n[redis]\nredis.key = push1,push2\n\n; mysql config\n[mysql]\nmysql."
},
{
"path": "constant/constants.go",
"chars": 1087,
"preview": "// Copyright 2022 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "constraint_test.go",
"chars": 7560,
"preview": "// Copyright 2024 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "detector/default_detector.go",
"chars": 4776,
"preview": "// Copyright 2025 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "detector/default_detector_test.go",
"chars": 9994,
"preview": "// Copyright 2025 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "detector/detector.go",
"chars": 1111,
"preview": "// Copyright 2025 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "effector/default_effector.go",
"chars": 2871,
"preview": "// Copyright 2018 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "effector/effector.go",
"chars": 1097,
"preview": "// Copyright 2018 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "enforcer.go",
"chars": 30739,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "enforcer_backslash_test.go",
"chars": 5831,
"preview": "// Copyright 2024 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "enforcer_cached.go",
"chars": 4759,
"preview": "// Copyright 2018 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "enforcer_cached_b_test.go",
"chars": 5948,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "enforcer_cached_gfunction_test.go",
"chars": 7330,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "enforcer_cached_synced.go",
"chars": 5015,
"preview": "// Copyright 2018 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "enforcer_cached_synced_test.go",
"chars": 2971,
"preview": "// Copyright 2018 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "enforcer_cached_test.go",
"chars": 2902,
"preview": "// Copyright 2018 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "enforcer_context.go",
"chars": 30091,
"preview": "// Copyright 2025 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "enforcer_context_interface.go",
"chars": 6199,
"preview": "// Copyright 2025 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "enforcer_context_test.go",
"chars": 6464,
"preview": "// Copyright 2025 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "enforcer_distributed.go",
"chars": 7009,
"preview": "package casbin\n\nimport (\n\t\"github.com/casbin/casbin/v3/model\"\n\t\"github.com/casbin/casbin/v3/persist\"\n)\n\n// DistributedEn"
},
{
"path": "enforcer_interface.go",
"chars": 9493,
"preview": "// Copyright 2019 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "enforcer_json_test.go",
"chars": 1714,
"preview": "package casbin\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/casbin/casbin/v3/model\"\n)\n\nfunc TestInvalidJsonRequest(t *t"
},
{
"path": "enforcer_synced.go",
"chars": 24671,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "enforcer_synced_test.go",
"chars": 21200,
"preview": "// Copyright 2018 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "enforcer_test.go",
"chars": 30018,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "enforcer_transactional.go",
"chars": 3541,
"preview": "// Copyright 2025 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "error_test.go",
"chars": 6311,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "errors/constraint_errors.go",
"chars": 1608,
"preview": "// Copyright 2024 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "errors/rbac_errors.go",
"chars": 1355,
"preview": "// Copyright 2018 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "examples/abac_model.conf",
"chars": 164,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[policy_effect]\ne = some(where (p.eft == "
},
{
"path": "examples/abac_not_using_policy_model.conf",
"chars": 201,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act, eft\n\n[policy_effect]\ne = some(where (p.ef"
},
{
"path": "examples/abac_rule_effect_policy.csv",
"chars": 115,
"preview": "p, alice, /data1, read, deny\np, alice, /data1, write, allow\np, bob, /data2, write, deny\np, bob, /data2, read, allow"
},
{
"path": "examples/abac_rule_model.conf",
"chars": 201,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub_rule, obj, act\n\n[policy_effect]\ne = some(where (p.ef"
},
{
"path": "examples/abac_rule_policy.csv",
"chars": 64,
"preview": "p, r.sub.Age > 18, /data1, read\np, r.sub.Age < 60, /data2, write"
},
{
"path": "examples/basic_inverse_policy.csv",
"chars": 42,
"preview": "p, alice, data1, write\np, bob, data2, read"
},
{
"path": "examples/basic_model.conf",
"chars": 194,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[policy_effect]\ne = some(where (p.eft == "
},
{
"path": "examples/basic_model_without_spaces.conf",
"chars": 190,
"preview": "[request_definition]\nr = sub,obj,act\n\n[policy_definition]\np = sub,obj,act\n\n[policy_effect]\ne = some(where (p.eft == allo"
},
{
"path": "examples/basic_policy.csv",
"chars": 42,
"preview": "p, alice, data1, read\np, bob, data2, write"
},
{
"path": "examples/basic_with_root_model.conf",
"chars": 213,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[policy_effect]\ne = some(where (p.eft == "
},
{
"path": "examples/basic_without_resources_model.conf",
"chars": 166,
"preview": "[request_definition]\nr = sub, act\n\n[policy_definition]\np = sub, act\n\n[policy_effect]\ne = some(where (p.eft == allow))\n\n["
},
{
"path": "examples/basic_without_resources_policy.csv",
"chars": 28,
"preview": "p, alice, read\np, bob, write"
},
{
"path": "examples/basic_without_users_model.conf",
"chars": 166,
"preview": "[request_definition]\nr = obj, act\n\n[policy_definition]\np = obj, act\n\n[policy_effect]\ne = some(where (p.eft == allow))\n\n["
},
{
"path": "examples/basic_without_users_policy.csv",
"chars": 30,
"preview": "p, data1, read\np, data2, write"
},
{
"path": "examples/biba_model.conf",
"chars": 293,
"preview": "[request_definition]\nr = sub, sub_level, obj, obj_level, act\n\n[policy_definition]\np = sub, obj, act\n\n[role_definition]\ng"
},
{
"path": "examples/blp_model.conf",
"chars": 294,
"preview": "[request_definition]\nr = sub, sub_level, obj, obj_level, act\n\n[policy_definition]\np = sub, obj, act\n\n[role_definition]\ng"
},
{
"path": "examples/comment_model.conf",
"chars": 254,
"preview": "[request_definition]\nr = sub, obj, act ; Request definition\n\n[policy_definition]\np = sub, obj, act \n\n[policy_effect]\ne ="
},
{
"path": "examples/error/error_model.conf",
"chars": 193,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition\np = sub, obj, act\n\n[policy_effect]\ne = some(where (p.eft == a"
},
{
"path": "examples/error/error_policy.csv",
"chars": 39,
"preview": "p, alice, data1, read\nbob, data2, write"
},
{
"path": "examples/eval_operator_model.conf",
"chars": 227,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub_rule, obj_rule, act\n\n[policy_effect]\ne = some(where "
},
{
"path": "examples/eval_operator_policy.csv",
"chars": 53,
"preview": "p, r.sub == 'admin' || false, r.obj == 'users', write"
},
{
"path": "examples/glob_model.conf",
"chars": 203,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[policy_effect]\ne = some(where (p.eft == "
},
{
"path": "examples/glob_policy.csv",
"chars": 75,
"preview": "p, u1, /foo/*, read\np, u2, /foo*, read\np, u3, /*/foo/*, read\np, u4, *, read"
},
{
"path": "examples/ipmatch_model.conf",
"chars": 201,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[policy_effect]\ne = some(where (p.eft == "
},
{
"path": "examples/ipmatch_policy.csv",
"chars": 59,
"preview": "p, 192.168.2.0/24, data1, read\np, 10.0.0.0/16, data2, write"
},
{
"path": "examples/keyget2_model.conf",
"chars": 243,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[policy_effect]\ne = some(where (p.eft == "
},
{
"path": "examples/keyget_model.conf",
"chars": 248,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[policy_effect]\ne = some(where (p.eft == "
},
{
"path": "examples/keymatch2_model.conf",
"chars": 213,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[policy_effect]\ne = some(where (p.eft == "
},
{
"path": "examples/keymatch2_policy.csv",
"chars": 81,
"preview": "p, alice, /alice_data/:resource, GET\np, alice, /alice_data2/:id/using/:resId, GET"
},
{
"path": "examples/keymatch_custom_model.conf",
"chars": 218,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[policy_effect]\ne = some(where (p.eft == "
},
{
"path": "examples/keymatch_model.conf",
"chars": 212,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[policy_effect]\ne = some(where (p.eft == "
},
{
"path": "examples/keymatch_policy.csv",
"chars": 165,
"preview": "p, alice, /alice_data/*, GET\np, alice, /alice_data/resource1, POST\n\np, bob, /alice_data/resource2, GET\np, bob, /bob_data"
},
{
"path": "examples/keymatch_with_rbac_in_domain.conf",
"chars": 288,
"preview": "[request_definition]\nr = sub, dom, obj, act\n\n[policy_definition]\np = sub, dom, obj, act\n\n[role_definition]\ng = _, _, _\n\n"
},
{
"path": "examples/keymatch_with_rbac_in_domain.csv",
"chars": 166,
"preview": "g, can_manage, can_use, *\n\np, can_manage, engines/*, *, (pause)|(resume)\np, can_use, engines/*, *, (attach)|(detach)\n\ng,"
},
{
"path": "examples/lbac_model.conf",
"chars": 501,
"preview": "[request_definition]\nr = sub, subject_confidentiality, subject_integrity, obj, object_confidentiality, object_integrity,"
},
{
"path": "examples/multiple_policy_definitions_model.conf",
"chars": 346,
"preview": "[request_definition]\nr = sub, obj, act\nr2 = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\np2= sub_rule, obj, act,"
},
{
"path": "examples/multiple_policy_definitions_policy.csv",
"chars": 170,
"preview": "p, data2_admin, data2, read\np2, r2.sub.Age > 18 && r2.sub.Age < 60, /data1, read, allow\np2, r2.sub.Age > 60 && r2.sub.Ag"
},
{
"path": "examples/object_conditions_model.conf",
"chars": 230,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, sub_rule, act\n\n[role_definition]\ng = _, _\n\n[policy_"
},
{
"path": "examples/object_conditions_policy.csv",
"chars": 121,
"preview": "p, alice, r.obj.price < 25, read\np, admin, r.obj.category_id = 2, read\np, bob, r.obj.author = bob, write\n\ng, alice, admi"
},
{
"path": "examples/orbac_model.conf",
"chars": 320,
"preview": "[request_definition]\nr = sub, org, obj, act\n\n[policy_definition]\np = role, activity, view, org\n\n[role_definition]\ng = _,"
},
{
"path": "examples/orbac_policy.csv",
"chars": 682,
"preview": "# Permission rules: role, activity, view, organization\np, manager, modify, document, org1\np, manager, consult, document,"
},
{
"path": "examples/pbac_model.conf",
"chars": 208,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub_rule, obj_rule, act\n\n[policy_effect]\ne = some(where "
},
{
"path": "examples/pbac_policy.csv",
"chars": 100,
"preview": "p, r.sub.Role == 'admin', r.obj.Type == 'doc', read\np, r.sub.Age >= 18, r.obj.Type == 'video', play\n"
},
{
"path": "examples/performance/rbac_with_pattern_large_scale_model.conf",
"chars": 252,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[role_definition]\ng = _, _, _\n\n[policy_ef"
},
{
"path": "examples/performance/rbac_with_pattern_large_scale_policy.csv",
"chars": 173005,
"preview": "# 132 policies / 3000 grouping policies / 300 subjuects / 6 roles\n# Policy - staff001\np, staff001, /orgs/{or"
},
{
"path": "examples/priority_indeterminate_policy.csv",
"chars": 36,
"preview": "p, alice, data1, read, indeterminate"
},
{
"path": "examples/priority_model.conf",
"chars": 223,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act, eft\n\n[role_definition]\ng = _, _\n\n[policy_"
},
{
"path": "examples/priority_model_enforce_context.conf",
"chars": 260,
"preview": "[request_definition]\nr = sub, obj, act\nr2 = sub, obj\n\n[policy_definition]\np = sub, obj, act, eft\n\n[role_definition]\ng = "
},
{
"path": "examples/priority_model_explicit.conf",
"chars": 233,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = priority, sub, obj, act, eft\n\n[role_definition]\ng = _, _"
},
{
"path": "examples/priority_model_explicit_customized.conf",
"chars": 260,
"preview": "[request_definition]\nr = subject, obj, act\n\n[policy_definition]\np = customized_priority, obj, act, eft, subject\n\n[role_d"
},
{
"path": "examples/priority_policy.csv",
"chars": 287,
"preview": "p, alice, data1, read, allow\np, data1_deny_group, data1, read, deny\np, data1_deny_group, data1, write, deny\np, alice, da"
},
{
"path": "examples/priority_policy_enforce_context.csv",
"chars": 288,
"preview": "p, alice, data1, read, allow\np, data1_deny_group, data1, read, deny\np, data1_deny_group, data1, write, deny\np, alice, da"
},
{
"path": "examples/priority_policy_explicit.csv",
"chars": 328,
"preview": "p, 10, data1_deny_group, data1, read, deny\np, 10, data1_deny_group, data1, write, deny\np, 10, data2_allow_group, data2, "
},
{
"path": "examples/priority_policy_explicit_customized.csv",
"chars": 328,
"preview": "p, 10, data1, read, deny, data1_deny_group\np, 10, data1, write, deny, data1_deny_group\np, 10, data2, read, allow, data2_"
},
{
"path": "examples/rbac_model.conf",
"chars": 223,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[role_definition]\ng = _, _\n\n[policy_effec"
},
{
"path": "examples/rbac_model_in_multi_line.conf",
"chars": 226,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[role_definition]\ng = _, _\n\n[policy_effec"
},
{
"path": "examples/rbac_model_matcher_using_in_op.conf",
"chars": 254,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[role_definition]\ng = _, _\n\n[policy_effec"
},
{
"path": "examples/rbac_model_matcher_using_in_op_bracket.conf",
"chars": 254,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[role_definition]\ng = _, _\n\n[policy_effec"
},
{
"path": "examples/rbac_policy.csv",
"chars": 121,
"preview": "p, alice, data1, read\np, bob, data2, write\np, data2_admin, data2, read\np, data2_admin, data2, write\ng, alice, data2_admi"
},
{
"path": "examples/rbac_with_all_pattern_model.conf",
"chars": 262,
"preview": "[request_definition]\nr = sub, dom, obj, act\n\n[policy_definition]\np = sub, dom, obj, act\n\n[role_definition]\ng = _, _, _\n\n"
},
{
"path": "examples/rbac_with_all_pattern_policy.csv",
"chars": 101,
"preview": "p, alice, domain1, book_group, read\np, alice, domain2, book_group, write\n\ng, /book/:id, book_group, *"
},
{
"path": "examples/rbac_with_constraints_model.conf",
"chars": 441,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[role_definition]\ng = _, _\n\n[constraint_d"
},
{
"path": "examples/rbac_with_cycle_policy.csv",
"chars": 172,
"preview": "p, alice, data1, read\np, bob, data2, write\np, data2_admin, data2, read\np, data2_admin, data2, write\ng, alice, data2_admi"
},
{
"path": "examples/rbac_with_deny_model.conf",
"chars": 260,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act, eft\n\n[role_definition]\ng = _, _\n\n[policy_"
},
{
"path": "examples/rbac_with_deny_policy.csv",
"chars": 179,
"preview": "p, alice, data1, read, allow\np, bob, data2, write, allow\np, data2_admin, data2, read, allow\np, data2_admin, data2, write"
},
{
"path": "examples/rbac_with_different_types_of_roles_model.conf",
"chars": 269,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, dom, obj, act\n\n[role_definition]\ng = _, _, _, (_, _"
},
{
"path": "examples/rbac_with_different_types_of_roles_policy.csv",
"chars": 339,
"preview": "p, role:owner, domain1, _, (read|write)\np, role:developer, domain1, _, read\n\np, role:owner, domain2, _, (read|write)\np, "
},
{
"path": "examples/rbac_with_domain_pattern_model.conf",
"chars": 262,
"preview": "[request_definition]\nr = sub, dom, obj, act\n\n[policy_definition]\np = sub, dom, obj, act\n\n[role_definition]\ng = _, _, _\n\n"
},
{
"path": "examples/rbac_with_domain_pattern_policy.csv",
"chars": 193,
"preview": "p, admin, domain1, data1, read\np, admin, domain1, data1, write\np, admin, domain2, data2, read\np, admin, domain2, data2, "
},
{
"path": "examples/rbac_with_domain_temporal_roles_model.conf",
"chars": 269,
"preview": "[request_definition]\nr = sub, dom, obj, act\n\n[policy_definition]\np = sub, dom, obj, act\n\n[role_definition]\ng = _, _, _, "
},
{
"path": "examples/rbac_with_domain_temporal_roles_policy.csv",
"chars": 991,
"preview": "p, alice, domain1, data1, read\np, alice, domain1, data1, write\np, data2_admin, domain2, data2, read\np, data2_admin, doma"
},
{
"path": "examples/rbac_with_domains_conditional_model.conf",
"chars": 417,
"preview": "[request_definition]\nr = sub, dom, obj, act\n\n[policy_definition]\np = sub, dom, obj, act\n\n[role_definition]\ng = _, _, _, "
},
{
"path": "examples/rbac_with_domains_conditional_policy.csv",
"chars": 466,
"preview": "p, test1, domain1, service1, /list\np, test1, domain1, service1, /get/:id/*\np, test1, domain1, service1, /add\np, test1, d"
},
{
"path": "examples/rbac_with_domains_model.conf",
"chars": 261,
"preview": "[request_definition]\nr = sub, dom, obj, act\n\n[policy_definition]\np = sub, dom, obj, act\n\n[role_definition]\ng = _, _, _\n\n"
},
{
"path": "examples/rbac_with_domains_policy.csv",
"chars": 173,
"preview": "p, admin, domain1, data1, read\np, admin, domain1, data1, write\np, admin, domain2, data2, read\np, admin, domain2, data2, "
},
{
"path": "examples/rbac_with_domains_policy2.csv",
"chars": 251,
"preview": "p, admin, domain1, data1, read\np, admin, domain1, data1, write\np, admin, domain2, data2, read\np, admin, domain2, data2, "
},
{
"path": "examples/rbac_with_hierarchy_policy.csv",
"chars": 217,
"preview": "p, alice, data1, read\np, bob, data2, write\np, data1_admin, data1, read\np, data1_admin, data1, write\np, data2_admin, data"
},
{
"path": "examples/rbac_with_hierarchy_with_domains_policy.csv",
"chars": 264,
"preview": "p, role:reader, domain1, data1, read\np, role:writer, domain1, data1, write\n\np, alice, domain1, data2, read\np, alice, dom"
},
{
"path": "examples/rbac_with_multiple_policy_model.conf",
"chars": 321,
"preview": "[request_definition]\nr = user, thing, action\n\n[policy_definition]\np = role, thing, action\np2 = role, action\n\n[policy_eff"
},
{
"path": "examples/rbac_with_multiple_policy_policy.csv",
"chars": 123,
"preview": "p, user, /data, GET\np, admin, /data, POST\n\np2, user, view\np2, admin, create\n\ng, admin, user\ng, alice, admin\ng2, alice, u"
},
{
"path": "examples/rbac_with_not_deny_model.conf",
"chars": 241,
"preview": "[request_definition]\r\nr = sub, obj, act\r\n\r\n[policy_definition]\r\np = sub, obj, act, eft\r\n\r\n[role_definition]\r\ng = _, _\r\n\r"
},
{
"path": "examples/rbac_with_pattern_model.conf",
"chars": 245,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[role_definition]\ng = _, _\ng2 = _, _\n\n[po"
},
{
"path": "examples/rbac_with_pattern_policy.csv",
"chars": 538,
"preview": "p, alice, /pen/1, GET\np, alice, /pen2/1, GET\np, book_admin, book_group, GET\np, pen_admin, pen_group, GET\np, *, pen3_grou"
},
{
"path": "examples/rbac_with_resource_roles_model.conf",
"chars": 235,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[role_definition]\ng = _, _\ng2 = _, _\n\n[po"
},
{
"path": "examples/rbac_with_resource_roles_policy.csv",
"chars": 153,
"preview": "p, alice, data1, read\np, bob, data2, write\np, data_group_admin, data_group, write\n\ng, alice, data_group_admin\ng2, data1,"
},
{
"path": "examples/rbac_with_temporal_roles_model.conf",
"chars": 231,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[role_definition]\ng = _, _, (_, _)\n\n[poli"
},
{
"path": "examples/rbac_with_temporal_roles_policy.csv",
"chars": 784,
"preview": "p, alice, data1, read\np, alice, data1, write\np, data2_admin, data2, read\np, data2_admin, data2, write\np, data3_admin, da"
},
{
"path": "examples/rebac_model.conf",
"chars": 257,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = role, obj_type, act\n\n[role_definition]\ng = _, _, _\ng2 = "
},
{
"path": "examples/rebac_policy.csv",
"chars": 112,
"preview": "p, collaborator, doc, read\n\ng, alice, doc1, collaborator\ng, bob, doc2, collaborator\n\ng2, doc1, doc\ng2, doc2, doc"
},
{
"path": "examples/subject_priority_model.conf",
"chars": 230,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act, eft\n\n[role_definition]\ng = _, _\n\n[policy_"
},
{
"path": "examples/subject_priority_model_with_domain.conf",
"chars": 313,
"preview": "[request_definition]\nr = sub, obj, dom, act\n\n[policy_definition]\np = sub, obj, dom, act, eft #sub can't change posit"
},
{
"path": "examples/subject_priority_policy.csv",
"chars": 268,
"preview": "p, root, data1, read, deny\np, admin, data1, read, deny\n\np, editor, data1, read, deny\np, subscriber, data1, read, deny\n\np"
},
{
"path": "examples/subject_priority_policy_with_domain.csv",
"chars": 200,
"preview": "p, admin, data1, domain1, write, deny\np, alice, data1, domain1, write, allow\np, admin, data2, domain2, write, deny\np, bo"
},
{
"path": "examples/syntax_matcher_model.conf",
"chars": 165,
"preview": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[policy_effect]\ne = some(where (p_eft == "
},
{
"path": "filter_test.go",
"chars": 7261,
"preview": "// Copyright 2018 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "frontend.go",
"chars": 1524,
"preview": "// Copyright 2020 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "frontend_old.go",
"chars": 1039,
"preview": "// Copyright 2021 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "frontend_old_test.go",
"chars": 2601,
"preview": "// Copyright 2021 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "frontend_test.go",
"chars": 2307,
"preview": "// Copyright 2020 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "go.mod",
"chars": 165,
"preview": "module github.com/casbin/casbin/v3\n\nrequire (\n\tgithub.com/bmatcuk/doublestar/v4 v4.6.1\n\tgithub.com/casbin/govaluate v1.3"
},
{
"path": "go.sum",
"chars": 519,
"preview": "github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I=\ngithub.com/bmatcuk/doublestar/v4"
},
{
"path": "internal_api.go",
"chars": 15645,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "lbac_test.go",
"chars": 3163,
"preview": "// Copyright 2025 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "log/default_logger.go",
"chars": 4134,
"preview": "// Copyright 2026 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "log/logger.go",
"chars": 1057,
"preview": "// Copyright 2025 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "log/types.go",
"chars": 1825,
"preview": "// Copyright 2025 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "logger_test.go",
"chars": 7265,
"preview": "// Copyright 2026 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "management_api.go",
"chars": 20545,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "management_api_b_test.go",
"chars": 5115,
"preview": "// Copyright 2020 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "management_api_test.go",
"chars": 14332,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "model/assertion.go",
"chars": 5164,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "model/constraint.go",
"chars": 7991,
"preview": "// Copyright 2024 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "model/function.go",
"chars": 2032,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "model/model.go",
"chars": 11265,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "model/model_test.go",
"chars": 4356,
"preview": "// Copyright 2019 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "model/policy.go",
"chars": 13232,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "model_b_test.go",
"chars": 7641,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "model_test.go",
"chars": 34380,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "orbac_test.go",
"chars": 3668,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "pbac_test.go",
"chars": 3759,
"preview": "// Copyright 2025 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "persist/adapter.go",
"chars": 2253,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "persist/adapter_context.go",
"chars": 1723,
"preview": "// Copyright 2023 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "persist/adapter_filtered.go",
"chars": 1038,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "persist/adapter_filtered_context.go",
"chars": 1137,
"preview": "// Copyright 2024 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "persist/batch_adapter.go",
"chars": 1100,
"preview": "// Copyright 2020 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "persist/batch_adapter_context.go",
"chars": 1208,
"preview": "// Copyright 2024 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "persist/cache/cache.go",
"chars": 1374,
"preview": "// Copyright 2021 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "persist/cache/cache_sync.go",
"chars": 1787,
"preview": "// Copyright 2021 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "persist/cache/default-cache.go",
"chars": 1638,
"preview": "// Copyright 2021 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "persist/dispatcher.go",
"chars": 1655,
"preview": "// Copyright 2020 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "persist/file-adapter/adapter.go",
"chars": 4068,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "persist/file-adapter/adapter_context.go",
"chars": 3542,
"preview": "// Copyright 2025 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "persist/file-adapter/adapter_filtered.go",
"chars": 3777,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "persist/file-adapter/adapter_filtered_context.go",
"chars": 1729,
"preview": "// Copyright 2025 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "persist/file-adapter/adapter_mock.go",
"chars": 3410,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "persist/persist_test.go",
"chars": 1662,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "persist/string-adapter/adapter.go",
"chars": 2543,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "persist/string-adapter/adapter_context.go",
"chars": 2202,
"preview": "// Copyright 2025 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "persist/string-adapter/adapter_test.go",
"chars": 2467,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "persist/transaction.go",
"chars": 2227,
"preview": "// Copyright 2025 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "persist/update_adapter.go",
"chars": 1287,
"preview": "// Copyright 2020 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "persist/update_adapter_context.go",
"chars": 1422,
"preview": "// Copyright 2024 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "persist/watcher.go",
"chars": 1284,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "persist/watcher_ex.go",
"chars": 2113,
"preview": "// Copyright 2020 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "persist/watcher_update.go",
"chars": 1206,
"preview": "// Copyright 2020 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "rbac/context_role_manager.go",
"chars": 2545,
"preview": "// Copyright 2023 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "rbac/default-role-manager/role_manager.go",
"chars": 37494,
"preview": "// Copyright 2017 The casbin Authors. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"Li"
}
]
// ... and 25 more files (download for full content)
About this extraction
This page contains the full source code of the apache/casbin GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 225 files (1018.9 KB), approximately 306.4k tokens, and a symbol index with 1396 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.