Commit

Author:

Hash:

Timestamp:

+91 -20 +/-8 browse

Kevin Schoon [me@kevinschoon.com]

eaa0fbd8ca871db8efb65ceda8f82b4f7c94a598

Sat, 11 Jul 2026 10:56:35 +0000 (2 months ago)

finish wiring identity into ayllu-shell
finish wiring identity into ayllu-shell

The identities section of Ayllu's configuration file now propagate to
the ayllu-shell interface correctly. Users need to specify the sshd
option PermitUserEnvironment=AYLLU_USER which `ayllu-keys` will now
specify after successful authentication. If the AYLLU_USER variable is
not set such as when you invoke the shell directly you are granted admin
access.
1diff --git a/Cargo.lock b/Cargo.lock
2index 9ead26e..2c3f3ef 100644
3--- a/Cargo.lock
4+++ b/Cargo.lock
5 @@ -371,6 +371,7 @@ version = "0.5.0"
6 dependencies = [
7 "ayllu_cmd",
8 "ayllu_config",
9+ "ayllu_database",
10 "ayllu_git",
11 "ayllu_identity",
12 "console",
13 diff --git a/ayllu-keys/src/main.rs b/ayllu-keys/src/main.rs
14index 3c4b97b..2404c1e 100644
15--- a/ayllu-keys/src/main.rs
16+++ b/ayllu-keys/src/main.rs
17 @@ -79,8 +79,12 @@ fn main() -> ExitCode {
18 );
19
20 if let Some(identity) = identify(&config, &args.ca_key_type, &args.certificate) {
21+ let ayllu_username = identity.username.to_string();
22 identity.authorized_keys.iter().for_each(|authorized_key| {
23- println!("restrict,pty {}", authorized_key.0);
24+ println!(
25+ "restrict,pty,environment=\"AYLLU_USER={ayllu_username}\" {}",
26+ authorized_key.0
27+ );
28 });
29 }
30
31 diff --git a/ayllu-shell/Cargo.toml b/ayllu-shell/Cargo.toml
32index 476f5cd..0c9f999 100644
33--- a/ayllu-shell/Cargo.toml
34+++ b/ayllu-shell/Cargo.toml
35 @@ -9,6 +9,7 @@ ayllu_cmd = { path = "../crates/cmd" }
36 ayllu_config = { path = "../crates/config" }
37 ayllu_git = { path = "../crates/git"}
38 ayllu_identity = { path = "../crates/identity" }
39+ ayllu_database = { path = "../crates/database" }
40
41 serde = { workspace = true }
42 thiserror.workspace = true
43 diff --git a/ayllu-shell/src/config.rs b/ayllu-shell/src/config.rs
44index 920fb73..ee5b8b8 100644
45--- a/ayllu-shell/src/config.rs
46+++ b/ayllu-shell/src/config.rs
47 @@ -40,7 +40,21 @@ pub struct Config {
48 pub identities: Vec<Identity>,
49 }
50
51- impl Configurable for Config {}
52+ impl Configurable for Config {
53+ fn validate(&mut self) -> Result<(), ayllu_config::Error> {
54+ if self
55+ .identities
56+ .iter()
57+ .find(|identity| identity.username.to_lowercase() == "ayllu")
58+ .is_some()
59+ {
60+ return Err(ayllu_config::Error::Validation(String::from(
61+ "An identity with the username Ayllu is not permitted",
62+ )));
63+ }
64+ Ok(())
65+ }
66+ }
67
68 #[cfg(test)]
69 mod test {
70 diff --git a/ayllu-shell/src/main.rs b/ayllu-shell/src/main.rs
71index 713edf7..a705de0 100644
72--- a/ayllu-shell/src/main.rs
73+++ b/ayllu-shell/src/main.rs
74 @@ -12,10 +12,24 @@ fn execute(args: Command) -> Result<(), Error> {
75 let username = args
76 .username
77 .unwrap_or(std::env::var("USER").expect("USER is not set"));
78- let _identity = config
79- .identities
80- .iter()
81- .find(|identity| identity.username == username);
82+ println!("System user is reported as: {username}");
83+ let ayllu_username = std::env::var("AYLLU_USER").ok();
84+ let identity = if let Some(ayllu_username) = ayllu_username {
85+ config
86+ .identities
87+ .iter()
88+ .find(|identity| identity.username == ayllu_username)
89+ } else {
90+ println!("AYLLU_USER was not specified and so you are an administrator!");
91+ Some(&ayllu_identity::Identity::administrator(&username))
92+ };
93+
94+ if identity.is_none() {
95+ panic!("BUG: User cannot be identitfied but the login was already authorized")
96+ };
97+
98+ let identity = identity.unwrap();
99+
100 match args.command {
101 Some(Subcommand::GitReceivePack { path }) => {
102 let resolved = if let Some(base_dir) = config.common.base_path {
103 @@ -73,7 +87,7 @@ fn execute(args: Command) -> Result<(), Error> {
104 }
105 None => {
106 print!("{}", config.shell.motd);
107- println!("\nYou are authenticated as: {username}\n");
108+ println!("\nYou are authenticated as: {identity}\n");
109 crate::ui::present(&config)?;
110 }
111 }
112 diff --git a/containers/Containerfile.debian-shell-test b/containers/Containerfile.debian-shell-test
113new file mode 100644
114index 0000000..59b23d3
115--- /dev/null
116+++ b/containers/Containerfile.debian-shell-test
117 @@ -0,0 +1,16 @@
118+ FROM docker.io/library/debian:testing
119+
120+ RUN apt-get update && apt-get install -yyq \
121+ openssh-server \
122+ git \
123+ sqlite3 \
124+ sudo
125+
126+ RUN useradd -m -d /home/ayllu -s /usr/bin/ayllu-shell ayllu
127+ RUN mkdir /src && chown ayllu:ayllu /src
128+
129+ RUN passwd -d root
130+ RUN passwd -d ayllu
131+
132+ USER ayllu
133+ WORKDIR /src
134 diff --git a/crates/identity/src/lib.rs b/crates/identity/src/lib.rs
135index 84f8f05..861abe1 100644
136--- a/crates/identity/src/lib.rs
137+++ b/crates/identity/src/lib.rs
138 @@ -43,3 +43,23 @@ pub struct Identity {
139 #[serde(default = "Vec::new")]
140 pub profiles: Vec<WebItem>,
141 }
142+
143+ impl std::fmt::Display for Identity {
144+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145+ write!(f, "{} ({})", self.username, self.email)
146+ }
147+ }
148+
149+ impl Identity {
150+ /// Return the administrator account based on the system user
151+ pub fn administrator(username: &str) -> Self {
152+ Identity {
153+ username: username.to_string(),
154+ authorized_keys: Vec::default(),
155+ email: String::default(),
156+ avatar: None,
157+ tagline: Some(String::from("Administrator")),
158+ profiles: Vec::default(),
159+ }
160+ }
161+ }
162 diff --git a/scripts/ayllu_shell_test.sh b/scripts/ayllu_shell_test.sh
163index 4dbeefc..daf24bb 100755
164--- a/scripts/ayllu_shell_test.sh
165+++ b/scripts/ayllu_shell_test.sh
166 @@ -4,27 +4,32 @@ set -e
167 # Your public SSH keys are passed into the container
168 # Expects a recent version of ayllu:multiuser-main on your system
169
170+ podman build \
171+ -f containers/Containerfile.debian-shell-test \
172+ -t localhost/ayllu-debian-shell-test .
173+
174 # NOTE that the session will terminate after closing the first connection.
175 DEBUGGING="-d"
176
177 AYLLU_SRC="$PWD"
178 AYLLU_SHELL_BINARY="$AYLLU_SRC/target/x86_64-unknown-linux-musl/debug/ayllu-shell"
179 AYLLU_KEYS_BINARY="$AYLLU_SRC/target/x86_64-unknown-linux-musl/debug/ayllu-keys"
180+ AYLLU_MIGRATE_BINARY="$AYLLU_SRC/target/x86_64-unknown-linux-musl/debug/ayllu-migrate"
181 LOCAL_SSH_PORT="2222"
182 KEYS_COMMAND="/usr/bin/ayllu-keys --ayllu-shell=/usr/bin/ayllu-shell %u %h %t %k"
183- IMAGE_NAME="registry.ayllu-forge.org/ayllu/ayllu:multiuser-main"
184- IMAGE_NAME="registry-auth.ayllu-forge.org/ayllu/ayllu:multiuser-main"
185+ IMAGE_NAME="localhost/ayllu-debian-shell-test"
186
187 TEST_CONFIG_FILE=config.ssh-test.toml
188
189 cargo build --target x86_64-unknown-linux-musl --package ayllu-keys
190 cargo build --target x86_64-unknown-linux-musl --package ayllu-shell
191+ cargo build --target x86_64-unknown-linux-musl --package ayllu-migrate
192
193 PUBLIC_KEY="$(find ~/.ssh -name '*.pub' -exec cat {} \; | head -n 1)"
194
195 make_cfg() {
196 cat >$TEST_CONFIG_FILE <<EOF
197- base_dir = "/usr/share/ayllu/repos"
198+ base_dir = "/var/lib/ayllu/repos"
199 log_level = "DEBUG"
200 [[collections]]
201 name = "demo"
202 @@ -40,21 +45,16 @@ EOF
203 init_env() {
204 cat<<EOF
205 passwd -d root
206- adduser -h /home/demo -D demo
207- passwd -d demo
208 passwd -d ayllu
209- ssh-keygen -A
210- mkdir -p /home/demo/.ssh
211- echo $PUBLIC_KEY > /home/demo/.ssh/authorized_keys
212- chmod 644 /home/demo/.ssh/authorized_keys
213- mkdir -p /usr/share/ayllu/repos/demo
214- chown -R ayllu:ayllu /usr/share/ayllu
215- /usr/sbin/sshd $DEBUGGING -D -o PermitTTY=yes -o PasswordAuthentication=no -o AuthorizedKeysCommand="$KEYS_COMMAND" -o AuthorizedKeysCommandUser=root
216+ mkdir /var/lib/ayllu && chown ayllu:ayllu /var/lib/ayllu
217+ sudo -u ayllu ayllu-migrate
218+ sudo -u ayllu mkdir -p /var/lib/ayllu/repos/demo
219+ /usr/sbin/sshd $DEBUGGING -D -o PermitTTY=yes -o PermitUserEnvironment="AYLLU_USER" -o PasswordAuthentication=no -o AuthorizedKeysCommand="$KEYS_COMMAND" -o AuthorizedKeysCommandUser=root
220 EOF
221 }
222
223 echo "To open a remote shell:"
224- echo "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no demo@127.0.0.1 -p 2222"
225+ echo "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no ayllu@127.0.0.1 -p 2222"
226 echo "Or run scripts/ayllu_shell_ssh.sh"
227
228 make_cfg
229 @@ -62,6 +62,7 @@ make_cfg
230 podman run \
231 --name ayllu-shell-test \
232 --rm --replace -ti --user root \
233+ -v $AYLLU_MIGRATE_BINARY:/usr/bin/ayllu-migrate \
234 -v $AYLLU_SHELL_BINARY:/usr/bin/ayllu-shell \
235 -v $AYLLU_KEYS_BINARY:/usr/bin/ayllu-keys \
236 -v $PWD/$TEST_CONFIG_FILE:/etc/ayllu/config.toml:ro \