feat: revert supporting for forbidden permission (#352)
This commit is contained in:
parent
3354b1face
commit
95eb648411
4 changed files with 14 additions and 42 deletions
|
@ -222,17 +222,17 @@ Dufs supports account based access control. You can control who can do what on w
|
||||||
|
|
||||||
```
|
```
|
||||||
dufs -a admin:admin@/:rw -a guest:guest@/
|
dufs -a admin:admin@/:rw -a guest:guest@/
|
||||||
dufs -a user:pass@/:rw,/dir1,/dir2:- -a @/
|
dufs -a user:pass@/:rw,/dir1 -a @/
|
||||||
```
|
```
|
||||||
|
|
||||||
1. Use `@` to separate the account and paths. No account means anonymous user.
|
1. Use `@` to separate the account and paths. No account means anonymous user.
|
||||||
2. Use `:` to separate the username and password of the account.
|
2. Use `:` to separate the username and password of the account.
|
||||||
3. Use `,` to separate paths.
|
3. Use `,` to separate paths.
|
||||||
4. Use path suffix `:rw`, `:ro`, `:-` to set permissions: `read-write`, `read-only`, `forbidden`. `:ro` can be omitted.
|
4. Use path suffix `:rw`/`:ro` set permissions: `read-write`/`read-only`. `:ro` can be omitted.
|
||||||
|
|
||||||
- `-a admin:admin@/:rw`: `admin` has complete permissions for all paths.
|
- `-a admin:admin@/:rw`: `admin` has complete permissions for all paths.
|
||||||
- `-a guest:guest@/`: `guest` has read-only permissions for all paths.
|
- `-a guest:guest@/`: `guest` has read-only permissions for all paths.
|
||||||
- `-a user:pass@/:rw,/dir1,/dir2:-`: `user` has read-write permissions for `/*`, has read-only permissions for `/dir1/*`, but is fordden for `/dir2/*`.
|
- `-a user:pass@/:rw,/dir1`: `user` has read-write permissions for `/*`, has read-only permissions for `/dir1/*`.
|
||||||
- `-a @/`: All paths is publicly accessible, everyone can view/download it.
|
- `-a @/`: All paths is publicly accessible, everyone can view/download it.
|
||||||
|
|
||||||
> There are no restrictions on using ':' and '@' characters in a password. For example, `user:pa:ss@1@/:rw` is valid, the password is `pa:ss@1`.
|
> There are no restrictions on using ':' and '@' characters in a password. For example, `user:pa:ss@1@/:rw` is valid, the password is `pa:ss@1`.
|
||||||
|
|
29
src/auth.rs
29
src/auth.rs
|
@ -147,7 +147,7 @@ impl AccessPaths {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_perm(&mut self, perm: AccessPerm) {
|
pub fn set_perm(&mut self, perm: AccessPerm) {
|
||||||
if !perm.inherit() {
|
if !perm.indexonly() {
|
||||||
self.perm = perm;
|
self.perm = perm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,7 +158,6 @@ impl AccessPaths {
|
||||||
None => (item, AccessPerm::ReadOnly),
|
None => (item, AccessPerm::ReadOnly),
|
||||||
Some((path, "ro")) => (path, AccessPerm::ReadOnly),
|
Some((path, "ro")) => (path, AccessPerm::ReadOnly),
|
||||||
Some((path, "rw")) => (path, AccessPerm::ReadWrite),
|
Some((path, "rw")) => (path, AccessPerm::ReadWrite),
|
||||||
Some((path, "-")) => (path, AccessPerm::Forbidden),
|
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
self.add(path, perm);
|
self.add(path, perm);
|
||||||
|
@ -193,9 +192,6 @@ impl AccessPaths {
|
||||||
.filter(|v| !v.is_empty())
|
.filter(|v| !v.is_empty())
|
||||||
.collect();
|
.collect();
|
||||||
let target = self.find_impl(&parts, self.perm)?;
|
let target = self.find_impl(&parts, self.perm)?;
|
||||||
if target.perm().forbidden() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
if writable && !target.perm().readwrite() {
|
if writable && !target.perm().readwrite() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -203,13 +199,13 @@ impl AccessPaths {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_impl(&self, parts: &[&str], perm: AccessPerm) -> Option<AccessPaths> {
|
fn find_impl(&self, parts: &[&str], perm: AccessPerm) -> Option<AccessPaths> {
|
||||||
let perm = if !self.perm.inherit() {
|
let perm = if !self.perm.indexonly() {
|
||||||
self.perm
|
self.perm
|
||||||
} else {
|
} else {
|
||||||
perm
|
perm
|
||||||
};
|
};
|
||||||
if parts.is_empty() {
|
if parts.is_empty() {
|
||||||
if perm.inherit() {
|
if perm.indexonly() {
|
||||||
return Some(self.clone());
|
return Some(self.clone());
|
||||||
} else {
|
} else {
|
||||||
return Some(AccessPaths::new(perm));
|
return Some(AccessPaths::new(perm));
|
||||||
|
@ -218,7 +214,7 @@ impl AccessPaths {
|
||||||
let child = match self.children.get(parts[0]) {
|
let child = match self.children.get(parts[0]) {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => {
|
None => {
|
||||||
if perm.inherit() {
|
if perm.indexonly() {
|
||||||
return None;
|
return None;
|
||||||
} else {
|
} else {
|
||||||
return Some(AccessPaths::new(perm));
|
return Some(AccessPaths::new(perm));
|
||||||
|
@ -233,7 +229,7 @@ impl AccessPaths {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn child_paths(&self, base: &Path) -> Vec<PathBuf> {
|
pub fn child_paths(&self, base: &Path) -> Vec<PathBuf> {
|
||||||
if !self.perm().inherit() {
|
if !self.perm().indexonly() {
|
||||||
return vec![base.to_path_buf()];
|
return vec![base.to_path_buf()];
|
||||||
}
|
}
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
|
@ -244,7 +240,7 @@ impl AccessPaths {
|
||||||
fn child_paths_impl(&self, output: &mut Vec<PathBuf>, base: &Path) {
|
fn child_paths_impl(&self, output: &mut Vec<PathBuf>, base: &Path) {
|
||||||
for (name, child) in self.children.iter() {
|
for (name, child) in self.children.iter() {
|
||||||
let base = base.join(name);
|
let base = base.join(name);
|
||||||
if child.perm().inherit() {
|
if child.perm().indexonly() {
|
||||||
child.child_paths_impl(output, &base);
|
child.child_paths_impl(output, &base);
|
||||||
} else {
|
} else {
|
||||||
output.push(base)
|
output.push(base)
|
||||||
|
@ -256,24 +252,19 @@ impl AccessPaths {
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
|
||||||
pub enum AccessPerm {
|
pub enum AccessPerm {
|
||||||
#[default]
|
#[default]
|
||||||
Inherit,
|
IndexOnly,
|
||||||
ReadOnly,
|
ReadOnly,
|
||||||
ReadWrite,
|
ReadWrite,
|
||||||
Forbidden,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AccessPerm {
|
impl AccessPerm {
|
||||||
pub fn inherit(&self) -> bool {
|
pub fn indexonly(&self) -> bool {
|
||||||
self == &AccessPerm::Inherit
|
self == &AccessPerm::IndexOnly
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn readwrite(&self) -> bool {
|
pub fn readwrite(&self) -> bool {
|
||||||
self == &AccessPerm::ReadWrite
|
self == &AccessPerm::ReadWrite
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn forbidden(&self) -> bool {
|
|
||||||
self == &AccessPerm::Forbidden
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn www_authenticate(res: &mut Response, args: &Args) -> Result<()> {
|
pub fn www_authenticate(res: &mut Response, args: &Args) -> Result<()> {
|
||||||
|
@ -576,7 +567,6 @@ mod tests {
|
||||||
paths.add("/dir1", AccessPerm::ReadWrite);
|
paths.add("/dir1", AccessPerm::ReadWrite);
|
||||||
paths.add("/dir2/dir21", AccessPerm::ReadWrite);
|
paths.add("/dir2/dir21", AccessPerm::ReadWrite);
|
||||||
paths.add("/dir2/dir21/dir211", AccessPerm::ReadOnly);
|
paths.add("/dir2/dir21/dir211", AccessPerm::ReadOnly);
|
||||||
paths.add("/dir2/dir21/dir212", AccessPerm::Forbidden);
|
|
||||||
paths.add("/dir2/dir22", AccessPerm::ReadOnly);
|
paths.add("/dir2/dir22", AccessPerm::ReadOnly);
|
||||||
paths.add("/dir2/dir22/dir221", AccessPerm::ReadWrite);
|
paths.add("/dir2/dir22/dir221", AccessPerm::ReadWrite);
|
||||||
paths.add("/dir2/dir23/dir231", AccessPerm::ReadWrite);
|
paths.add("/dir2/dir23/dir231", AccessPerm::ReadWrite);
|
||||||
|
@ -621,6 +611,5 @@ mod tests {
|
||||||
Some(AccessPaths::new(AccessPerm::ReadOnly))
|
Some(AccessPaths::new(AccessPerm::ReadOnly))
|
||||||
);
|
);
|
||||||
assert_eq!(paths.find("dir2/dir21/dir211/file", true), None);
|
assert_eq!(paths.find("dir2/dir21/dir211/file", true), None);
|
||||||
assert_eq!(paths.find("dir2/dir21/dir212", false), None);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -375,7 +375,7 @@ impl Server {
|
||||||
"PROPFIND" => {
|
"PROPFIND" => {
|
||||||
if is_dir {
|
if is_dir {
|
||||||
let access_paths =
|
let access_paths =
|
||||||
if access_paths.perm().inherit() && authorization.is_none() {
|
if access_paths.perm().indexonly() && authorization.is_none() {
|
||||||
// see https://github.com/sigoden/dufs/issues/229
|
// see https://github.com/sigoden/dufs/issues/229
|
||||||
AccessPaths::new(AccessPerm::ReadOnly)
|
AccessPaths::new(AccessPerm::ReadOnly)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1230,7 +1230,7 @@ impl Server {
|
||||||
access_paths: AccessPaths,
|
access_paths: AccessPaths,
|
||||||
) -> Result<Vec<PathItem>> {
|
) -> Result<Vec<PathItem>> {
|
||||||
let mut paths: Vec<PathItem> = vec![];
|
let mut paths: Vec<PathItem> = vec![];
|
||||||
if access_paths.perm().inherit() {
|
if access_paths.perm().indexonly() {
|
||||||
for name in access_paths.child_names() {
|
for name in access_paths.child_names() {
|
||||||
let entry_path = entry_path.join(name);
|
let entry_path = entry_path.join(name);
|
||||||
self.add_pathitem(&mut paths, base_path, &entry_path).await;
|
self.add_pathitem(&mut paths, base_path, &entry_path).await;
|
||||||
|
|
|
@ -144,23 +144,6 @@ fn auth_readonly(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
|
||||||
fn auth_forbidden(
|
|
||||||
#[with(&["--auth", "user:pass@/:rw,/dir1:-", "-A"])] server: TestServer,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let url = format!("{}file1", server.url());
|
|
||||||
let resp = fetch!(b"PUT", &url)
|
|
||||||
.body(b"abc".to_vec())
|
|
||||||
.send_with_digest_auth("user", "pass")?;
|
|
||||||
assert_eq!(resp.status(), 201);
|
|
||||||
let url = format!("{}dir1/file1", server.url());
|
|
||||||
let resp = fetch!(b"PUT", &url)
|
|
||||||
.body(b"abc".to_vec())
|
|
||||||
.send_with_digest_auth("user", "pass")?;
|
|
||||||
assert_eq!(resp.status(), 403);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn auth_nest(
|
fn auth_nest(
|
||||||
#[with(&["--auth", "user:pass@/:rw", "--auth", "user2:pass2@/", "--auth", "user3:pass3@/dir1:rw", "-A"])]
|
#[with(&["--auth", "user:pass@/:rw", "--auth", "user2:pass2@/", "--auth", "user3:pass3@/dir1:rw", "-A"])]
|
||||||
|
|
Loading…
Reference in a new issue