ktconvertor 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 pengfei liu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,32 @@
1
+ Metadata-Version: 2.4
2
+ Name: ktconvertor
3
+ Version: 0.1.0
4
+ Summary: This tool can convert kerberos ticket of format .kirbi to standard MIT CCACHE format
5
+ Author-email: Pengfei Liu <pengfei.liu@casd.eu>
6
+ License: MIT
7
+ Keywords: kerberos,ccache
8
+ Requires-Python: >=3.11
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: pyasn1
12
+ Requires-Dist: minikerberos
13
+ Requires-Dist: asn1crypto
14
+ Requires-Dist: typer
15
+ Provides-Extra: dev
16
+ Requires-Dist: pytest>=7.0; extra == "dev"
17
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
18
+ Requires-Dist: black>=23.0; extra == "dev"
19
+ Requires-Dist: isort>=5.12; extra == "dev"
20
+ Requires-Dist: mypy>=1.0; extra == "dev"
21
+ Dynamic: license-file
22
+
23
+ # KtConvertor
24
+
25
+ The objective of this project is to convert a kerberos ticket from format `.kirbi` to MIT Kerberos cache file.
26
+
27
+
28
+ We use the `ccache.py` of the project [minikerberos](https://github.com/skelsec/minikerberos/blob/main/minikerberos/common/ccache.py)
29
+
30
+ ##
31
+
32
+
@@ -0,0 +1,10 @@
1
+ # KtConvertor
2
+
3
+ The objective of this project is to convert a kerberos ticket from format `.kirbi` to MIT Kerberos cache file.
4
+
5
+
6
+ We use the `ccache.py` of the project [minikerberos](https://github.com/skelsec/minikerberos/blob/main/minikerberos/common/ccache.py)
7
+
8
+ ##
9
+
10
+
@@ -0,0 +1,41 @@
1
+ [project]
2
+ name = "ktconvertor"
3
+ version = "0.1.0"
4
+ description = "This tool can convert kerberos ticket of format .kirbi to standard MIT CCACHE format"
5
+ readme = "README.md"
6
+ requires-python = ">=3.11"
7
+
8
+ authors = [
9
+ { name = "Pengfei Liu", email = "pengfei.liu@casd.eu" }
10
+ ]
11
+ license = { text = "MIT" }
12
+
13
+ keywords = ["kerberos", "ccache", ]
14
+
15
+ dependencies = ["pyasn1", "minikerberos","asn1crypto", "typer"
16
+ ]
17
+
18
+ [project.optional-dependencies]
19
+ # Development dependencies (install with: pip install -e ".[dev]")
20
+ dev = [
21
+ "pytest>=7.0",
22
+ "pytest-cov>=4.0",
23
+ "black>=23.0", # Code formatter
24
+ "isort>=5.12", # Import sorter
25
+ "mypy>=1.0", # Added for type checking
26
+ ]
27
+
28
+ [project.scripts]
29
+ # This allows the user to run 'convert-tgt' directly in the terminal
30
+ convert-tgt = "ktconvertor.main:app"
31
+
32
+ [build-system]
33
+ requires = ["setuptools>=61.0"]
34
+ build-backend = "setuptools.build_meta"
35
+
36
+ # Modern project tip: Add configuration for your tools here
37
+ [tool.black]
38
+ line-length = 88
39
+
40
+ [tool.isort]
41
+ profile = "black"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
File without changes
@@ -0,0 +1,118 @@
1
+ import base64
2
+ import getpass
3
+ import os
4
+ import sys
5
+ from pathlib import Path
6
+ from typing import Optional
7
+
8
+ from asn1crypto import core
9
+ from minikerberos.common.ccache import CCACHE, Credential, CCACHEPrincipal, Times, Keyblock, CCACHEOctetString
10
+ from minikerberos.common.kirbi import Kirbi
11
+ from minikerberos.protocol.asn1_structs import EncKrbCredPart, TicketFlags, Ticket
12
+
13
+
14
+ def from_kirbi(kirbi: Kirbi):
15
+ krbcred = kirbi.kirbiobj.native
16
+ c = Credential()
17
+ enc_credinfo = EncKrbCredPart.load(krbcred['enc-part']['cipher']).native
18
+ ticket_info = enc_credinfo['ticket-info'][0]
19
+
20
+ c.client = CCACHEPrincipal.from_asn1(ticket_info['pname'], ticket_info['prealm'])
21
+ # yaaaaay 4 additional weirdness!!!!
22
+ # if sname name-string contains a realm as well htne impacket will crash miserably :(
23
+ if len(ticket_info['sname']['name-string']) > 2 and ticket_info['sname']['name-string'][-1].upper() == ticket_info[
24
+ 'srealm'].upper():
25
+ print('SNAME contains the realm as well, trimming it')
26
+ t = ticket_info['sname']
27
+ t['name-string'] = t['name-string'][:-1]
28
+ c.server = CCACHEPrincipal.from_asn1(t, ticket_info['srealm'])
29
+ else:
30
+ c.server = CCACHEPrincipal.from_asn1(ticket_info['sname'], ticket_info['srealm'])
31
+
32
+ c.time = Times.from_asn1(ticket_info)
33
+ c.key = Keyblock.from_asn1(ticket_info['key'])
34
+ c.is_skey = 0 # not sure!
35
+
36
+ c.tktflags = TicketFlags(ticket_info['flags']).cast(core.IntegerBitString).native
37
+ c.num_address = 0
38
+ c.num_authdata = 0
39
+ c.ticket = CCACHEOctetString.from_asn1(
40
+ Ticket(krbcred['tickets'][0]).dump()) # kirbi only stores one ticket per file
41
+ c.second_ticket = CCACHEOctetString.empty()
42
+
43
+ return c
44
+
45
+
46
+ def gen_cache_path(user: Optional[str] = None) -> str:
47
+ """
48
+ Generate MIT Kerberos ccache file path following OS-specific standards.
49
+
50
+ Refined to prioritize XDG specs on Linux and robust path handling on Windows.
51
+ """
52
+ if sys.platform == "darwin":
53
+ # macOS typically uses API-based credential caches (KCM), not flat files.
54
+ raise NotImplementedError("macOS uses CCAPI; file-based paths are non-standard.")
55
+
56
+ if os.name == "nt":
57
+ # Windows best practice: Use USERPROFILE or LOCALAPPDATA for caches
58
+ user = user or getpass.getuser()
59
+ base = Path(os.environ.get("USERPROFILE", f"C:/Users/{user}"))
60
+ return (base / f"krb5cc_{user}").as_posix()
61
+
62
+ # Linux / Unix / POSIX
63
+ # 1. Check for XDG_RUNTIME_DIR (Modern Linux standard, e.g., /run/user/1000)
64
+ # 2. Fallback to /tmp with UID
65
+ uid = os.getuid()
66
+ runtime_dir = os.environ.get("XDG_RUNTIME_DIR")
67
+
68
+ if runtime_dir:
69
+ base_path = Path(runtime_dir)
70
+ else:
71
+ base_path = Path("/tmp")
72
+
73
+ return (base_path / f"krb5cc_{uid}").as_posix()
74
+
75
+
76
+ def convert_kirbi(src:str, dest:str=None)->str:
77
+ """
78
+ This function convert the kirbi format to MIT ccache format.
79
+ :param src: The path of source .kirbi file which contains the tgt binary in base64 format
80
+ :param dest: The path of converted MIT ccache file
81
+ :return:
82
+ """
83
+ # 1. Standardize path handling using Pathlib
84
+ # This handles ../, ./, absolute paths, and OS-specific separators ( \ vs / )
85
+ src_path = Path(src).expanduser().resolve()
86
+
87
+ if not src_path.exists():
88
+ raise FileNotFoundError(f"Source kirbi file not found: {src_path}")
89
+
90
+ # 2. Use context managers for safe File I/O
91
+ # This ensures the file handle is closed even if decoding fails
92
+ try:
93
+ with src_path.open("rb") as f:
94
+ kirbi_b64 = f.read()
95
+
96
+ # 3. Decode Base64 to raw bytes
97
+ kirbi_bytes = base64.b64decode(kirbi_b64)
98
+ except Exception as e:
99
+ raise ValueError(f"Failed to read or decode kirbi file: {e}")
100
+
101
+ # 4. Process the credential cache
102
+ cc = CCACHE.from_bytes(kirbi_bytes)
103
+
104
+ # 5. Determine destination
105
+ if dest:
106
+ dest_path = Path(dest).expanduser().resolve()
107
+ else:
108
+ # Fallback to our logic from the previous gen_cache_path function
109
+ dest_path = Path(gen_cache_path())
110
+
111
+ # Ensure the parent directory for the destination exists
112
+ dest_path.parent.mkdir(parents=True, exist_ok=True)
113
+
114
+ # 6. Write ticket to the file path
115
+ final_path = dest_path.as_posix()
116
+ cc.to_file(final_path)
117
+
118
+ return final_path
@@ -0,0 +1,32 @@
1
+ Metadata-Version: 2.4
2
+ Name: ktconvertor
3
+ Version: 0.1.0
4
+ Summary: This tool can convert kerberos ticket of format .kirbi to standard MIT CCACHE format
5
+ Author-email: Pengfei Liu <pengfei.liu@casd.eu>
6
+ License: MIT
7
+ Keywords: kerberos,ccache
8
+ Requires-Python: >=3.11
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: pyasn1
12
+ Requires-Dist: minikerberos
13
+ Requires-Dist: asn1crypto
14
+ Requires-Dist: typer
15
+ Provides-Extra: dev
16
+ Requires-Dist: pytest>=7.0; extra == "dev"
17
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
18
+ Requires-Dist: black>=23.0; extra == "dev"
19
+ Requires-Dist: isort>=5.12; extra == "dev"
20
+ Requires-Dist: mypy>=1.0; extra == "dev"
21
+ Dynamic: license-file
22
+
23
+ # KtConvertor
24
+
25
+ The objective of this project is to convert a kerberos ticket from format `.kirbi` to MIT Kerberos cache file.
26
+
27
+
28
+ We use the `ccache.py` of the project [minikerberos](https://github.com/skelsec/minikerberos/blob/main/minikerberos/common/ccache.py)
29
+
30
+ ##
31
+
32
+
@@ -0,0 +1,14 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/main.py
5
+ src/ktconvertor/__init__.py
6
+ src/ktconvertor/convertor.py
7
+ src/ktconvertor.egg-info/PKG-INFO
8
+ src/ktconvertor.egg-info/SOURCES.txt
9
+ src/ktconvertor.egg-info/dependency_links.txt
10
+ src/ktconvertor.egg-info/entry_points.txt
11
+ src/ktconvertor.egg-info/requires.txt
12
+ src/ktconvertor.egg-info/top_level.txt
13
+ tests/test_convertor.py
14
+ tests/test_genCachePath.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ convert-tgt = ktconvertor.main:app
@@ -0,0 +1,11 @@
1
+ pyasn1
2
+ minikerberos
3
+ asn1crypto
4
+ typer
5
+
6
+ [dev]
7
+ pytest>=7.0
8
+ pytest-cov>=4.0
9
+ black>=23.0
10
+ isort>=5.12
11
+ mypy>=1.0
@@ -0,0 +1,2 @@
1
+ ktconvertor
2
+ main
@@ -0,0 +1,53 @@
1
+ import typer
2
+ from pathlib import Path
3
+ from typing import Optional
4
+ from rich.console import Console
5
+
6
+ # Adjust the import to match your package structure
7
+ from ktconvertor.convertor import convert_kirbi
8
+
9
+ # Initialize console for professional-looking output
10
+ console = Console()
11
+
12
+ app = typer.Typer(
13
+ name="krbconvertor",
14
+ help="CLI tool to convert Kerberos .kirbi tickets to MIT CCACHE format.",
15
+ rich_markup_mode="rich"
16
+ )
17
+
18
+
19
+ @app.command()
20
+ def convert(
21
+ kirbi_path: Path = typer.Argument(
22
+ ...,
23
+ exists=True,
24
+ file_okay=True,
25
+ dir_okay=False,
26
+ readable=True,
27
+ resolve_path=True,
28
+ help="Path to the input .kirbi ticket file."
29
+ ),
30
+ ccache_path: Optional[Path] = typer.Option(
31
+ None,
32
+ "--output", "-o",
33
+ writable=True,
34
+ help="Path for the output .ccache file. If omitted, uses the default OS cache path."
35
+ ),
36
+ ):
37
+ """
38
+ Convert a Kerberos .kirbi ticket to .ccache format.
39
+ """
40
+ try:
41
+ # Convert Path object back to string if your core function requires it,
42
+ # though it's better if convert_kirbi handles Path objects.
43
+ final_path = convert_kirbi(str(kirbi_path), str(ccache_path) if ccache_path else None)
44
+
45
+ console.print(f"[bold green]✓ Success:[/bold green] Ticket converted to [cyan]{final_path}[/cyan]")
46
+
47
+ except Exception as e:
48
+ console.print(f"[bold red]✗ Error:[/bold red] {e}")
49
+ raise typer.Exit(code=1)
50
+
51
+
52
+ if __name__ == "__main__":
53
+ app()
@@ -0,0 +1,16 @@
1
+ from ktconvertor.convertor import convert_kirbi
2
+
3
+
4
+ def test_convertor_with_given_path():
5
+ kirbi = "C:/Users/pliu/Documents/git/krbTicketConvertor/tests/tmp/tgt.kirbi"
6
+ ccache = "C:/Users/pliu/Documents/git/krbTicketConvertor/tests/tmp/tgt.ccache"
7
+
8
+ convert_kirbi(kirbi, ccache)
9
+
10
+ def test_convertor_with_default_path():
11
+ kirbi = "C:/Users/pliu/Documents/git/krbTicketConvertor/tests/tmp/tgt.kirbi"
12
+ convert_kirbi(kirbi)
13
+
14
+ def test_convertor_with_relative_path():
15
+ kirbi = "./tests/tmp/tgt.kirbi"
16
+ convert_kirbi(kirbi)
@@ -0,0 +1,55 @@
1
+ import os
2
+ import sys
3
+ import pytest
4
+ from unittest.mock import patch, MagicMock
5
+ from pathlib import Path
6
+
7
+
8
+ from ktconvertor.convertor import gen_cache_path
9
+
10
+
11
+ class TestGenCachePath:
12
+
13
+ @patch("sys.platform", "darwin")
14
+ def test_macos_raises_error(self):
15
+ """Ensure macOS triggers the expected NotImplementedError."""
16
+ with pytest.raises(NotImplementedError, match="macOS uses CCAPI"):
17
+ gen_cache_path()
18
+
19
+ @patch("os.name", "nt")
20
+ @patch("getpass.getuser", return_value="alice")
21
+ @patch.dict(os.environ, {"USERPROFILE": "C:\\Users\\alice"})
22
+ def test_windows_path_generation(self, mock_getuser):
23
+ """Verify Windows path logic using environment variables."""
24
+ path = gen_cache_path()
25
+ # Pathlib handles the slash conversion, .as_posix() ensures forward slashes
26
+ assert path == "C:/Users/alice/krb5cc_alice"
27
+
28
+
29
+ @patch("os.name", "nt")
30
+ @patch.dict(os.environ, {"USERPROFILE": "C:\\Users\\bob"})
31
+ def test_explicit_user_override(self):
32
+ """Ensure providing a 'user' argument overrides the system user."""
33
+ path = gen_cache_path(user="admin")
34
+ assert path == "C:/Users/bob/krb5cc_admin"
35
+
36
+ ####### The linux os test will fail if you run under windows ###############
37
+ # the os module is dynamic; attributes like getuid or setuid simply do not exist when Python runs on Windows.
38
+ @patch("os.name", "posix")
39
+ @patch("sys.platform", "linux")
40
+ @patch("os.getuid", return_value=1000)
41
+ @patch.dict(os.environ, {}, clear=True)
42
+ def test_linux_fallback_path(self, mock_uid):
43
+ """Verify fallback to /tmp when XDG_RUNTIME_DIR is missing.
44
+ """
45
+ path = gen_cache_path()
46
+ assert path == "/tmp/krb5cc_1000"
47
+
48
+ @patch("os.name", "posix")
49
+ @patch("sys.platform", "linux")
50
+ @patch("os.getuid", return_value=1000)
51
+ @patch.dict(os.environ, {"XDG_RUNTIME_DIR": "/run/user/1000"})
52
+ def test_linux_xdg_path(self, mock_uid):
53
+ """Verify preference for XDG_RUNTIME_DIR on modern Linux systems."""
54
+ path = gen_cache_path()
55
+ assert path == "/run/user/1000/krb5cc_1000"