• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! API for authenticating peer
2 //! Based on https://grpc.github.io/grpc/core/md_doc_server_side_auth.html
3 
4 use std::ffi::CStr;
5 use std::marker::PhantomData;
6 use std::ptr::NonNull;
7 
8 use crate::grpc_sys::{
9     self, grpc_auth_context, grpc_auth_property, grpc_auth_property_iterator, grpc_call,
10 };
11 
12 /// To perform server-side authentication, gRPC exposes the authentication context
13 /// for each call. The context exposes important authentication-related information
14 /// about the RPC such as the type of security/authentication type being used and
15 /// the peer identity.
16 ///
17 /// The authentication context is structured as a multi-map of key-value pairs -
18 /// the auth properties. In addition to that, for authenticated RPCs, the set of
19 /// properties corresponding to a selected key will represent the verified identity
20 /// of the caller - the peer identity.
21 ///
22 /// The contents of the auth properties are populated by an auth interceptor within
23 /// gRPC Core. The interceptor also chooses which property key will act as the peer
24 /// identity (e.g. for client certificate authentication this property will be
25 /// `x509_common_name` or `x509_subject_alternative_name`).
26 pub struct AuthContext {
27     ctx: NonNull<grpc_auth_context>,
28 }
29 
30 /// Binding to gRPC Core AuthContext
31 impl AuthContext {
from_call_ptr(call: *mut grpc_call) -> Option<Self>32     pub(crate) unsafe fn from_call_ptr(call: *mut grpc_call) -> Option<Self> {
33         NonNull::new(grpc_sys::grpc_call_auth_context(call)).map(|ctx| AuthContext { ctx })
34     }
35 
36     /// The name of the property gRPC Core has chosen as main peer identity property,
37     /// if any.
peer_identity_property_name(&self) -> Option<&str>38     pub fn peer_identity_property_name(&self) -> Option<&str> {
39         unsafe {
40             let p = grpc_sys::grpc_auth_context_peer_identity_property_name(self.ctx.as_ref());
41             if p.is_null() {
42                 None
43             } else {
44                 Some(CStr::from_ptr(p).to_str().expect("valid UTF-8 data"))
45             }
46         }
47     }
48 
49     /// `true` if the client has provided a valid certificate (or other auth method
50     /// considered valid by gRPC).
51     /// `false` in non-secure scenarios.
peer_is_authenticated(&self) -> bool52     pub fn peer_is_authenticated(&self) -> bool {
53         unsafe { grpc_sys::grpc_auth_context_peer_is_authenticated(self.ctx.as_ref()) != 0 }
54     }
55 
56     /// `AuthContext[peer_identity_property_name()]`
57     ///
58     /// There may be several of them (for instance if `x509_subject_alternative_name` is selected)
peer_identity(&self) -> AuthPropertyIter59     pub fn peer_identity(&self) -> AuthPropertyIter {
60         unsafe {
61             // grpc_auth_context_peer_identity returns empty_iterator when self.ctx is NULL
62             let iter = grpc_sys::grpc_auth_context_peer_identity(self.ctx.as_ref());
63             AuthPropertyIter {
64                 iter,
65                 _lifetime: PhantomData,
66             }
67         }
68     }
69 }
70 
71 impl<'a> IntoIterator for &'a AuthContext {
72     type Item = AuthProperty<'a>;
73     type IntoIter = AuthPropertyIter<'a>;
74 
75     /// Iterate over the AuthContext properties
into_iter(self) -> Self::IntoIter76     fn into_iter(self) -> Self::IntoIter {
77         unsafe {
78             // grpc_auth_context_property_iterator returns empty_iterator when self.ctx is NULL
79             let iter = grpc_sys::grpc_auth_context_property_iterator(self.ctx.as_ref());
80             AuthPropertyIter {
81                 iter,
82                 _lifetime: PhantomData,
83             }
84         }
85     }
86 }
87 
88 impl Drop for AuthContext {
drop(&mut self)89     fn drop(&mut self) {
90         unsafe { grpc_sys::grpc_auth_context_release(self.ctx.as_ptr()) }
91     }
92 }
93 
94 pub struct AuthPropertyIter<'a> {
95     iter: grpc_auth_property_iterator,
96     _lifetime: PhantomData<&'a grpc_auth_property_iterator>,
97 }
98 
99 impl<'a> Iterator for AuthPropertyIter<'a> {
100     type Item = AuthProperty<'a>;
101 
next(&mut self) -> Option<Self::Item>102     fn next(&mut self) -> Option<Self::Item> {
103         // grpc_auth_property_iterator_next returns empty_iterator when self.iter is NULL
104         let prop = unsafe { grpc_sys::grpc_auth_property_iterator_next(&mut self.iter) };
105         if prop.is_null() {
106             None
107         } else {
108             Some(AuthProperty {
109                 prop,
110                 _lifetime: PhantomData,
111             })
112         }
113     }
114 }
115 
116 /// Auth properties are elements of the AuthContext. They have a name
117 /// (a key of type string) and a value which can be a string or binary data.
118 pub struct AuthProperty<'a> {
119     prop: *const grpc_auth_property,
120     _lifetime: PhantomData<&'a grpc_auth_property>,
121 }
122 
123 impl<'a> AuthProperty<'a> {
name(&self) -> &'a str124     pub fn name(&self) -> &'a str {
125         unsafe { CStr::from_ptr((*self.prop).name) }
126             .to_str()
127             .expect("Auth property name should be valid UTF-8 data")
128     }
129 
value(&self) -> &'a [u8]130     pub fn value(&self) -> &'a [u8] {
131         unsafe {
132             std::slice::from_raw_parts((*self.prop).value as *const u8, (*self.prop).value_length)
133         }
134     }
135 
value_str(&self) -> Result<&'a str, std::str::Utf8Error>136     pub fn value_str(&self) -> Result<&'a str, std::str::Utf8Error> {
137         std::str::from_utf8(self.value())
138     }
139 }
140