extern crate actix;
extern crate actix_web;
extern crate futures;
extern crate oxide_auth;
extern crate url;
#[path = "support/actix.rs"]
mod support;
use std::thread;
use actix::{Actor, Addr};
use actix_web::{server, App, HttpRequest, HttpResponse};
use actix_web::middleware::Logger;
use futures::{Future, future};
use oxide_auth::frontends::actix::{AsActor, OAuth, OAuthFailure, OAuthResponse, OwnerConsent, PreGrant, ResourceProtection};
use oxide_auth::frontends::actix::{authorization, access_token, refresh, resource};
use oxide_auth::frontends::simple::endpoint::FnSolicitor;
use oxide_auth::primitives::prelude::*;
static DENY_TEXT: &str = "<html>
This page should be accessed via an oauth token from the client in the example. Click
<a href=\"http://localhost:8020/authorize?response_type=code&client_id=LocalClient\">
here</a> to begin the authorization process.
</html>
";
#[derive(Clone)]
struct State {
registrar: Addr<AsActor<ClientMap>>,
authorizer: Addr<AsActor<AuthMap<RandomGenerator>>>,
issuer: Addr<AsActor<TokenMap<RandomGenerator>>>,
scopes: &'static [Scope],
}
pub fn main() {
let mut sys = actix::System::new("HttpServerClient");
let mut clients = ClientMap::new();
let client = Client::public("LocalClient", "http://localhost:8021/endpoint".parse().unwrap(), "default".parse().unwrap()); clients.register_client(client);
let authorizer = AuthMap::new(RandomGenerator::new(16));
let issuer = TokenMap::new(RandomGenerator::new(16));
let scopes = vec!["default".parse().unwrap()].into_boxed_slice();
let scopes: &'static _ = Box::leak(scopes);
let state = State {
registrar: AsActor(clients).start(),
authorizer: AsActor(authorizer).start(),
issuer: AsActor(issuer).start(),
scopes,
};
server::new(
move || App::with_state(state.clone())
.middleware(Logger::default())
.resource("/authorize", |r| {
r.get().a(|req: &HttpRequest<State>| {
let state = req.state().clone();
req.oauth2()
.and_then(|request| authorization(
state.registrar,
state.authorizer,
FnSolicitor(|_: &mut _, grant: &_| in_progress_response(grant)),
request,
OAuthResponse::default()))
.map(|response| response.get_or_consent_with(consent_form))
.map_err(OAuthFailure::from)
});
r.post().a(|req: &HttpRequest<State>| {
let state = req.state().clone();
let allowed = req.query_string().contains("allow");
req.oauth2()
.and_then(move |request| authorization(
state.registrar,
state.authorizer,
FnSolicitor(move |_: &mut _, grant: &_| consent_decision(allowed, grant)),
request,
OAuthResponse::default()))
.map(OAuthResponse::unwrap)
.map_err(OAuthFailure::from)
});
})
.resource("/token", |r| r.post().a(|req: &HttpRequest<State>| {
let state = req.state().clone();
req.oauth2()
.and_then(|request| access_token(
state.registrar,
state.authorizer,
state.issuer,
request,
OAuthResponse::default()))
.map(OAuthResponse::unwrap)
.map_err(OAuthFailure::from)
}))
.resource("/refresh", |r| r.post().a(|req: &HttpRequest<State>| {
let state = req.state().clone();
req.oauth2()
.and_then(|request| refresh(
state.registrar,
state.issuer,
request,
OAuthResponse::default()))
.map(OAuthResponse::unwrap)
.map_err(OAuthFailure::from)
}))
.resource("/", |r| r.get().a(|req: &HttpRequest<State>| {
let state = req.state().clone();
req.oauth2()
.map_err(ResourceProtection::Error)
.and_then(|request| resource(
state.issuer,
state.scopes,
request,
OAuthResponse::default()))
.map(|_grant| HttpResponse::Ok()
.content_type("text/plain")
.body("Hello world!"))
.or_else(|result| match result {
ResourceProtection::Respond(response) => {
let mut response = response.unwrap();
response.set_body(DENY_TEXT);
Ok(response)
},
ResourceProtection::Error(err) => Err(OAuthFailure::from(err)),
})
}))
)
.bind("localhost:8020")
.expect("Failed to bind to socket")
.start();
server::new(support::dummy_client)
.bind("localhost:8021")
.expect("Failed to start dummy client")
.start();
let _: Result<(), ()> = sys.block_on(future::lazy(|| {
let _ = thread::spawn(support::open_in_browser);
future::ok(())
}));
let _ = sys.run();
}
fn consent_form(grant: PreGrant) -> HttpResponse {
HttpResponse::Ok()
.content_type("text/html")
.body(support::consent_page_html("/authorize".into(), &grant))
}
fn in_progress_response(grant: &PreGrant) -> OwnerConsent<OAuthResponse> {
OwnerConsent::InProgress(OAuthResponse::consent_form(grant.clone()))
}
fn consent_decision(allowed: bool, _: &PreGrant) -> OwnerConsent<OAuthResponse> {
if allowed {
OwnerConsent::Authorized("dummy user".to_string())
} else {
OwnerConsent::Denied
}
}