Rust 백엔드 및 SPA 프런트엔드가 포함된 JumpCloud SSO

18287 단어 vuetutorialwebdevrust
지난 주 동안 저는 SPA 프런트엔드를 위한 JumpCloud 통합 작업을 했습니다. 나 자신의 미래 참조를 위해 나만의 튜토리얼을 작성하기로 결정했습니다.
이 글을 읽으시면 저는 JumpCloud와 관련이 없습니다. Rust 부분만 찾으면 소개를 건너뛰고 #Integration 섹션으로 건너뛸 수 있습니다.

점프클라우드란?



JumpCloud를 모른다면 JumpCloud는 ID 관리 플랫폼입니다. 타사 앱에 대한 많은 통합을 제공합니다.
일반적으로 엔터프라이즈 회사이고 ID를 하나의 ID로 통합하려는 경우 JumpCloud와 통합할 수 있습니다.
참고로 https://jumpcloud.com에서 자세한 내용을 확인할 수 있습니다.

SAML을 사용한 JumpCloud SSO



이 문서에서는 SSO 및 SAML에 대해 자세히 다루지 않습니다. 자세한 내용을 알고 싶다면 https://support.google.com/a/answer/6262987?hl=en으로 이동하십시오. 읽어보시면 좋은 참고가 됩니다.

시작하려면 JumpCloud에 가입하고 관리자로 로그인해야 합니다. 새 SSO 앱을 만들기 전에 로컬에서 인증서와 개인 키를 만들 수 있습니다.

# To create cert file
$ openssl req -new -x509 -sha256 -key private.pem -out cert.pem -days 1095
# To create private key
$ openssl genrsa -out private.pem 2048


이제 JumpCloud에서 SSO 앱을 생성하고 생성된 인증서와 개인 키를 업로드할 수 있습니다. 그런 다음 ACS 필드를 http://localhost:8000/saml/acs로 채웁니다. SAML 응답 어설션을 위한 엔드포인트 핸들러가 됩니다.

Rust로 SAML 응답 처리



단계별 절차는 다음과 같습니다.
  • 새 녹 프로젝트를 만듭니다. $ mkdir jumcloud-rust && cargo init .
  • 화물 종속성 추가
  • JumpCloud 메타데이터 복사
  • JumpCloud SP 엔터티 ID 복사
  • 아래 코드를 JumpCloud 메타데이터 및 JumpCloud SP 엔티티 ID로 바꿉니다
  • .
    cargo.toml
    [package]
    name = "jumpcloudrust"
    version = "0.1.0"
    edition = "2021"
    
    # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
    
    [dependencies]
    openssl = "0.10"
    openssl-sys = "0.9"
    openssl-probe = "0.1.2"
    samael="0.0.9"
    tokio = { version = "1", features = ["full"] }
    warp="0.3"
    reqwest = { version = "0.11", features = ["json"] }
    
    [profile.release]
    lto = "fat"
    codegen-units = 1
    

    src/main.rs
    use samael::metadata::{EntityDescriptor};
    use samael::service_provider::ServiceProviderBuilder;
    use std::collections::HashMap;
    use std::fs;
    use warp::{Filter};
    use warp::http::{StatusCode};
    
    #[tokio::main]
    async fn main() -> Result<(), Box<dyn std::error::Error>> {
        openssl_probe::init_ssl_cert_env_vars();
    
        let jc_metadata_str = "--- replace with your JC SSO App Metadata ---";
        println!("{}",jc_metadata_str);
        let idp_metadata: EntityDescriptor = samael::metadata::de::from_str(&jc_metadata_str)?;
    
        let pub_key = openssl::x509::X509::from_pem(&fs::read("./cert.pem")?)?;
        let private_key = openssl::rsa::Rsa::private_key_from_pem(&fs::read("./private.pem")?)?;
    
        let sp = ServiceProviderBuilder::default()
            .entity_id("--- replace with your entity id ---".to_string())
            .key(private_key)
            .certificate(pub_key)
            .allow_idp_initiated(true)
            .idp_metadata(idp_metadata)
            .acs_url("http://localhost:8000/saml/acs".to_string())
            .slo_url("http://localhost:8000/saml/slo".to_string())
            .build()?;
    
        let metadata = sp.metadata()?.to_xml()?;
    
        let metadata_route = warp::get()
            .and(warp::path("metadata"))
            .map(move || metadata.clone());
    
        let acs_route = warp::post()
            .and(warp::path("acs"))
            .and(warp::body::form())
            .map(move |s: HashMap<String, String>| {
                if let Some(encoded_resp) = s.get("SAMLResponse") {
                    println!("{:?}", encoded_resp);
    
                    let sp_res = sp.parse_response(encoded_resp, &["a_possible_request_id".to_string()]);
                    return match sp_res {
                        Ok(resp) => {
                            println!("{:?}", resp);
    
                            let cookie_val = format!("token={}; Path=/; Max-Age=1209600", "abc");
    
                            warp::http::Response::builder()
                                .header("set-cookie", string_to_static_str(cookie_val))
                                .header("Location", "http://localhost:3000/")
                                .status(StatusCode::FOUND)
                                .body("".to_string())
                        },
                        Err(e) => warp::http::Response::builder()
                            .status(StatusCode::BAD_REQUEST)
                            .body(e.to_string())
                    }
                }
    
                return warp::http::Response::builder()
                    .status(StatusCode::FORBIDDEN)
                    .body("Error FORBIDDEN".to_string())
            });
    
        let saml_routes = warp::path("saml").and(acs_route.or(metadata_route));
        warp::serve(saml_routes).run(([127, 0, 0, 1], 8000)).await;
    
        Ok(())
    }
    
    fn string_to_static_str(s: String) -> &'static str {
        Box::leak(s.into_boxed_str())
    }
    


    이제 앱을 실행합니다. 터미널로 이동하여 cargo run --release를 입력합니다. 그것이 BE 부분입니다. 전체 Rust 구현에 대해서는 내 (github)[github.com/rhzs/rust-saml-jumpcloud-sso]를 참조하세요.

    SPA 프런트엔드를 위한 JumpCloud 준비



    프런트엔드 부분은 간단한 구현입니다. 터미널로 이동하여 clone my github repo .

    여기에는 다음 구현 및 논리가 포함됩니다.
  • JumpCloud 로그인 리디렉션 버튼이 있는 로그인 페이지
  • 로그인 후 홈 페이지 및 시작 메시지
  • 로그인하지 않은 상태에서 홈 페이지를 클릭하려고 하면 로그인 페이지로 리디렉션됩니다.
  • 자격 증명을 지우는 로그아웃 버튼

  • 합치기



    함께 실행하려면 다음을 수행하십시오.
  • 2개의 서로 다른 터미널을 엽니다. 하나는 백엔드용이고 다른 하나는 프런트엔드용입니다.
  • 프런트엔드를 열고 JumpCloud로 로그인을 클릭하십시오
  • .
  • JumpCloud 로그인 페이지로 리디렉션됩니다.
  • 로그인하면 응용 프로그램으로 리디렉션되어야 합니다.
  • JumpCloud는 입력 ACS 핸들러 필드에서 API를 호출하여 백엔드에 응답합니다. 그래서 http://localhost:8000/saml/acs를 넣으면
  • JumpCloud는 지정된 API 끝점에 인코딩된 양식 작업으로 POST를 수행합니다. 백엔드에서 백엔드는 이 요청을 수락하고 SAML 어설션을 수행한 다음 프런트엔드로 리디렉션하도록 지시합니다.

  • 비올라!! 성공입니다! 축하합니다! JumpCloud SSO를 SPA 프런트엔드 및 자체 Rust 백엔드와 통합할 수 있습니다.


    이 가이드는 2022년 7월 3일 현재 100% 작동하는 것으로 확인되었습니다.
    튜토리얼에 정보가 부족하더라도 용서해 주십시오. 자세한 튜토리얼이 아니라 자체 문서를 작성하기 위한 것입니다.

    좋은 웹페이지 즐겨찾기