#sso #oauth2 #authentication #qonfucius

qonfucius-sso-utility

A Rust implementation of Qonfucius SSO for resource servers

4 releases

0.1.0-alpha.4 Apr 23, 2021
0.1.0-alpha.3 Apr 21, 2021
0.1.0-alpha.2 Nov 26, 2020

#15 in #sso

MIT license

19KB
213 lines

Qonfucius SSO Utility

pipeline status MIT licensed Crates.io docs

qonfucius-sso-utility is a simple tool to implement Qonfucius's SSO and handle token and scope verification on your back-end resource web app.

Features

To be able to use UtilityError as an actix-web response error you need to enable the following actix feature:

qonfucius-sso-utility = { version = "0.1.0-alpha", features = ["actix"] }

Be warned as the current implementation provokes this:

  • ParsingError will render a StatusCode::INTERNAL_SERVER_ERROR (500)
  • TokenError will render a StatusCode::UNAUTHORIZED (401)
  • ScopeError will render a StatusCode::FORBIDDEN (403)

I can work for you but we highly recommend a custom implementation on your side.

Environment variables s

Name Description
SSO_URI URL of the SSO instance
SSO_SELF_DOMAIN Domain of your application to identify your scopes

Setup

After installation you need to define a Scoped Resource type, usually an enum that implements the following traits:

  • Eq
  • Hash
  • Clone
  • Debug
  • FromStr

Example

This is the definition used in one of our own API.

use qonfucius_sso_utility::UtilityError;

#[derive(Clone, Debug, PartialEq, Hash, Eq)]
pub enum ScopedResource {
    Content,
    ContentSchema,
    Media,
}

impl FromStr for ScopedResource {
    type Err = UtilityError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_lowercase().as_str() {
            "content" => Ok(Self::Content),
            "content_schema" => Ok(Self::ContentSchema),
            "media" => Ok(Self::Media),
            _ => Err(UtilityError::ParsingError(String::from(
                r#"Scoped Resource part must be 'content', 'content_schema' or 'media"#,
            ))),
        }
    }
}

Once your type is declared you can use it as the T value of Scope<T>

Scopes

When you verify a token the scope will look like this:

{
  "scopes": {
    "my_domain": ["content::read", "notifications::write", "medias::write"],
    "not_my_domain": ["some_resource::read", "stuff::write"]
  }
}

The env var SELF_SSO_DOMAIN will define which subset to use, and the scopes will be parsed. Each scope looks like this: $RESOURCE::$ACL. While the $ACL is either write or read, the $RESOURCE is for you to define like we showed earlier.

Steps

To verify a token and access authorized scopes the steps are the following:

async fn main() {
    let token = "TokenToCheck";
    // Calls the SSO to verify the token and retrieves the `Token` response
    let token_response = Token::verify_token(&token).await.unwrap();
    // Parse the scopes matching your domain (`SSO_SELF_DOMAIN`)
    let scope: Scope<ScopedResource> = token_response.parse_scope().unwrap();
    // you can now use the `Scope<T>` object to handle your authorizations
}

Dependencies

~4–11MB
~211K SLoC