geforkt von mirrored/vaultwarden
Documented U2F, removed debug prints, and documented missing features
Dieser Commit ist enthalten in:
Ursprung
970863ffb1
Commit
819622e310
4 geänderte Dateien mit 58 neuen und 34 gelöschten Zeilen
71
README.md
71
README.md
|
@ -11,13 +11,14 @@ _*Note, that this project is not associated with the [Bitwarden](https://bitward
|
||||||
- [Updating the bitwarden image](#updating-the-bitwarden-image)
|
- [Updating the bitwarden image](#updating-the-bitwarden-image)
|
||||||
- [Configuring bitwarden service](#configuring-bitwarden-service)
|
- [Configuring bitwarden service](#configuring-bitwarden-service)
|
||||||
- [Disable registration of new users](#disable-registration-of-new-users)
|
- [Disable registration of new users](#disable-registration-of-new-users)
|
||||||
|
- [Enabling HTTPS](#enabling-https)
|
||||||
|
- [Enabling U2F authentication](#enabling-u2f-authentication)
|
||||||
- [Changing persistent data location](#changing-persistent-data-location)
|
- [Changing persistent data location](#changing-persistent-data-location)
|
||||||
- [/data prefix:](#data-prefix)
|
- [/data prefix:](#data-prefix)
|
||||||
- [database name and location](#database-name-and-location)
|
- [database name and location](#database-name-and-location)
|
||||||
- [attachments location](#attachments-location)
|
- [attachments location](#attachments-location)
|
||||||
- [icons cache](#icons-cache)
|
- [icons cache](#icons-cache)
|
||||||
- [Changing the API request size limit](#changing-the-api-request-size-limit)
|
- [Changing the API request size limit](#changing-the-api-request-size-limit)
|
||||||
- [Enabling HTTPS](#enabling-https)
|
|
||||||
- [Other configuration](#other-configuration)
|
- [Other configuration](#other-configuration)
|
||||||
- [Building your own image](#building-your-own-image)
|
- [Building your own image](#building-your-own-image)
|
||||||
- [Building binary](#building-binary)
|
- [Building binary](#building-binary)
|
||||||
|
@ -41,6 +42,14 @@ Basically full implementation of Bitwarden API is provided including:
|
||||||
* Vault API support
|
* Vault API support
|
||||||
* Serving the static files for Vault interface
|
* Serving the static files for Vault interface
|
||||||
* Website icons API
|
* Website icons API
|
||||||
|
* Authenticator and U2F support
|
||||||
|
|
||||||
|
## Missing features
|
||||||
|
* Email confirmation
|
||||||
|
* Other two-factor systems:
|
||||||
|
* YubiKey OTP (if your key supports U2F, you can use that)
|
||||||
|
* Duo
|
||||||
|
* Email codes
|
||||||
|
|
||||||
## Docker image usage
|
## Docker image usage
|
||||||
|
|
||||||
|
@ -109,6 +118,44 @@ docker run -d --name bitwarden \
|
||||||
mprasil/bitwarden:latest
|
mprasil/bitwarden:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Enabling HTTPS
|
||||||
|
To enable HTTPS, you need to configure the `ROCKET_TLS`.
|
||||||
|
|
||||||
|
The values to the option must follow the format:
|
||||||
|
```
|
||||||
|
ROCKET_TLS={certs="/path/to/certs.pem",key="/path/to/key.pem"}
|
||||||
|
```
|
||||||
|
Where:
|
||||||
|
- certs: a path to a certificate chain in PEM format
|
||||||
|
- key: a path to a private key file in PEM format for the certificate in certs
|
||||||
|
|
||||||
|
```sh
|
||||||
|
docker run -d --name bitwarden \
|
||||||
|
-e ROCKET_TLS={certs='"/ssl/certs.pem",key="/ssl/key.pem"}' \
|
||||||
|
-v /ssl/keys/:/ssl/ \
|
||||||
|
-v /bw-data/:/data/ \
|
||||||
|
-v /icon_cache/ \
|
||||||
|
-p 443:443 \
|
||||||
|
mprasil/bitwarden:latest
|
||||||
|
```
|
||||||
|
Note that you need to mount ssl files and you need to forward appropriate port.
|
||||||
|
|
||||||
|
### Enabling U2F authentication
|
||||||
|
To enable U2F authentication, you must be serving bitwarden_rs from an HTTPS domain with a valid certificate (Either using the included
|
||||||
|
HTTPS options or with a reverse proxy). We recommend using a free certificate from Let's Encrypt.
|
||||||
|
|
||||||
|
After that, you need to set the `DOMAIN` environment variable to the same address from where bitwarden_rs is being served:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
docker run -d --name bitwarden \
|
||||||
|
-e DOMAIN=https://bw.domain.tld \
|
||||||
|
-v /bw-data/:/data/ \
|
||||||
|
-p 80:80 \
|
||||||
|
mprasil/bitwarden:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that the value has to include the `https://` and it may include a port at the end (in the format of `https://bw.domain.tld:port`) when not using `443`.
|
||||||
|
|
||||||
### Changing persistent data location
|
### Changing persistent data location
|
||||||
|
|
||||||
#### /data prefix:
|
#### /data prefix:
|
||||||
|
@ -184,28 +231,6 @@ docker run -d --name bitwarden \
|
||||||
mprasil/bitwarden:latest
|
mprasil/bitwarden:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
### Enabling HTTPS
|
|
||||||
To enable HTTPS, you need to configure the `ROCKET_TLS`.
|
|
||||||
|
|
||||||
The values to the option must follow the format:
|
|
||||||
```
|
|
||||||
ROCKET_TLS={certs="/path/to/certs.pem",key="/path/to/key.pem"}
|
|
||||||
```
|
|
||||||
Where:
|
|
||||||
- certs: a path to a certificate chain in PEM format
|
|
||||||
- key: a path to a private key file in PEM format for the certificate in certs
|
|
||||||
|
|
||||||
```sh
|
|
||||||
docker run -d --name bitwarden \
|
|
||||||
-e ROCKET_TLS={certs='"/ssl/certs.pem",key="/ssl/key.pem"}' \
|
|
||||||
-v /ssl/keys/:/ssl/ \
|
|
||||||
-v /bw-data/:/data/ \
|
|
||||||
-v /icon_cache/ \
|
|
||||||
-p 443:443 \
|
|
||||||
mprasil/bitwarden:latest
|
|
||||||
```
|
|
||||||
Note that you need to mount ssl files and you need to forward appropriate port.
|
|
||||||
|
|
||||||
### Other configuration
|
### Other configuration
|
||||||
|
|
||||||
Though this is unlikely to be required in small deployment, you can fine-tune some other settings like number of workers using environment variables that are processed by [Rocket](https://rocket.rs), please see details in [documentation](https://rocket.rs/guide/configuration/#environment-variables).
|
Though this is unlikely to be required in small deployment, you can fine-tune some other settings like number of workers using environment variables that are processed by [Rocket](https://rocket.rs), please see details in [documentation](https://rocket.rs/guide/configuration/#environment-variables).
|
||||||
|
|
|
@ -217,6 +217,10 @@ lazy_static! {
|
||||||
|
|
||||||
#[post("/two-factor/get-u2f", data = "<data>")]
|
#[post("/two-factor/get-u2f", data = "<data>")]
|
||||||
fn generate_u2f(data: JsonUpcase<PasswordData>, headers: Headers, conn: DbConn) -> JsonResult {
|
fn generate_u2f(data: JsonUpcase<PasswordData>, headers: Headers, conn: DbConn) -> JsonResult {
|
||||||
|
if !CONFIG.domain_set {
|
||||||
|
err!("`DOMAIN` environment variable is not set. U2F disabled")
|
||||||
|
}
|
||||||
|
|
||||||
let data: PasswordData = data.into_inner().data;
|
let data: PasswordData = data.into_inner().data;
|
||||||
|
|
||||||
if !headers.user.check_valid_password(&data.MasterPasswordHash) {
|
if !headers.user.check_valid_password(&data.MasterPasswordHash) {
|
||||||
|
@ -299,8 +303,6 @@ fn activate_u2f(data: JsonUpcase<EnableU2FData>, headers: Headers, conn: DbConn)
|
||||||
.delete(&conn)
|
.delete(&conn)
|
||||||
.expect("Error deleting U2F register challenge");
|
.expect("Error deleting U2F register challenge");
|
||||||
|
|
||||||
println!("RegisterResponse {:#?}", &data.DeviceResponse);
|
|
||||||
|
|
||||||
let response_copy: RegisterResponseCopy =
|
let response_copy: RegisterResponseCopy =
|
||||||
serde_json::from_str(&data.DeviceResponse).expect("Can't parse RegisterResponse data");
|
serde_json::from_str(&data.DeviceResponse).expect("Can't parse RegisterResponse data");
|
||||||
|
|
||||||
|
@ -388,7 +390,6 @@ impl Into<Registration> for RegistrationCopy {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _parse_registrations(registations: &str) -> Vec<Registration> {
|
fn _parse_registrations(registations: &str) -> Vec<Registration> {
|
||||||
println!("Registrations {:#?}", registations);
|
|
||||||
let registrations_copy: Vec<RegistrationCopy> =
|
let registrations_copy: Vec<RegistrationCopy> =
|
||||||
serde_json::from_str(registations).expect("Can't parse RegistrationCopy data");
|
serde_json::from_str(registations).expect("Can't parse RegistrationCopy data");
|
||||||
|
|
||||||
|
@ -418,8 +419,6 @@ pub fn validate_u2f_login(user_uuid: &str, response: &str, conn: &DbConn) -> Api
|
||||||
|
|
||||||
let challenge = match tf_challenge {
|
let challenge = match tf_challenge {
|
||||||
Some(tf_challenge) => {
|
Some(tf_challenge) => {
|
||||||
println!("challenge {:#?}", &tf_challenge.data);
|
|
||||||
|
|
||||||
let challenge: Challenge = serde_json::from_str(&tf_challenge.data)
|
let challenge: Challenge = serde_json::from_str(&tf_challenge.data)
|
||||||
.expect("Can't parse U2fLoginChallenge data");
|
.expect("Can't parse U2fLoginChallenge data");
|
||||||
tf_challenge
|
tf_challenge
|
||||||
|
@ -437,8 +436,6 @@ pub fn validate_u2f_login(user_uuid: &str, response: &str, conn: &DbConn) -> Api
|
||||||
|
|
||||||
let registrations = _parse_registrations(&twofactor.data);
|
let registrations = _parse_registrations(&twofactor.data);
|
||||||
|
|
||||||
println!("response {:#?}", response);
|
|
||||||
|
|
||||||
let response: SignResponse =
|
let response: SignResponse =
|
||||||
serde_json::from_str(response).expect("Can't parse SignResponse data");
|
serde_json::from_str(response).expect("Can't parse SignResponse data");
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,8 @@ use util::{self, JsonMap};
|
||||||
|
|
||||||
use api::{ApiResult, JsonResult};
|
use api::{ApiResult, JsonResult};
|
||||||
|
|
||||||
|
use CONFIG;
|
||||||
|
|
||||||
pub fn routes() -> Vec<Route> {
|
pub fn routes() -> Vec<Route> {
|
||||||
routes![login]
|
routes![login]
|
||||||
}
|
}
|
||||||
|
@ -216,7 +218,7 @@ fn _json_err_twofactor(providers: &[i32], user_uuid: &str, conn: &DbConn) -> Api
|
||||||
match TwoFactorType::from_i32(*provider) {
|
match TwoFactorType::from_i32(*provider) {
|
||||||
Some(TwoFactorType::Authenticator) => { /* Nothing to do for TOTP */ }
|
Some(TwoFactorType::Authenticator) => { /* Nothing to do for TOTP */ }
|
||||||
|
|
||||||
Some(TwoFactorType::U2f) => {
|
Some(TwoFactorType::U2f) if CONFIG.domain_set => {
|
||||||
let request = two_factor::generate_u2f_login(user_uuid, conn)?;
|
let request = two_factor::generate_u2f_login(user_uuid, conn)?;
|
||||||
let mut challenge_list = Vec::new();
|
let mut challenge_list = Vec::new();
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
///
|
///
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! err {
|
macro_rules! err {
|
||||||
($err:expr, $err_desc:expr, $msg:expr) => {
|
($err:expr, $err_desc:expr, $msg:expr) => {{
|
||||||
|
println!("ERROR: {}", $msg);
|
||||||
err_json!(json!({
|
err_json!(json!({
|
||||||
"error": $err,
|
"error": $err,
|
||||||
"error_description": $err_desc,
|
"error_description": $err_desc,
|
||||||
|
@ -13,14 +14,13 @@ macro_rules! err {
|
||||||
"Object": "error"
|
"Object": "error"
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
};
|
}};
|
||||||
($msg:expr) => { err!("default_error", "default_error_description", $msg) }
|
($msg:expr) => { err!("default_error", "default_error_description", $msg) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! err_json {
|
macro_rules! err_json {
|
||||||
($expr:expr) => {{
|
($expr:expr) => {{
|
||||||
println!("ERROR: {}", $expr);
|
|
||||||
return Err($crate::rocket::response::status::BadRequest(Some($crate::rocket_contrib::Json($expr))));
|
return Err($crate::rocket::response::status::BadRequest(Some($crate::rocket_contrib::Json($expr))));
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
Laden …
In neuem Issue referenzieren