@@ -11,8 +11,10 @@ use prometheus::{Encoder, Registry};
1111use anyhow:: { Error , Result } ;
1212use futures:: future;
1313use futures:: task:: { Context , Poll } ;
14+ use hyper:: header:: AUTHORIZATION ;
15+ use hyper:: http:: HeaderValue ;
1416use hyper:: service:: Service ;
15- use hyper:: { Body , Method , Request , Response , StatusCode } ;
17+ use hyper:: { Body , HeaderMap , Method , Request , Response , StatusCode } ;
1618use log:: { debug, error} ;
1719
1820#[ derive( Clone , Debug ) ]
@@ -59,9 +61,10 @@ impl Service<Request<Body>> for MetricProvider {
5961 fn call ( & mut self , req : Request < Body > ) -> Self :: Future {
6062 debug ! ( "New Request to endpoint {}" , req. uri( ) . path( ) ) ;
6163
62- let output = match ( req. method ( ) , req. uri ( ) . path ( ) ) {
64+ let authorized = is_auth_token_valid ( & self . config . secret , req. headers ( ) ) ;
65+ let output = match ( req. method ( ) , req. uri ( ) . path ( ) , authorized) {
6366 // Metrics handler
64- ( & Method :: GET , "/metrics" ) => {
67+ ( & Method :: GET , "/metrics" , true ) => {
6568 let encoder = prometheus:: TextEncoder :: new ( ) ;
6669 let mut buffer = Vec :: < u8 > :: new ( ) ;
6770 match self . gather_with_encoder ( encoder, & mut buffer) {
@@ -78,6 +81,11 @@ impl Service<Request<Body>> for MetricProvider {
7881 }
7982 }
8083 }
84+ // Unauthorized request
85+ ( & Method :: GET , "/metrics" , false ) => Response :: builder ( )
86+ . status ( StatusCode :: UNAUTHORIZED )
87+ . body ( Body :: empty ( ) )
88+ . unwrap ( ) ,
8189 // All other paths and methods
8290 _ => Response :: builder ( )
8391 . status ( StatusCode :: OK )
@@ -89,6 +97,22 @@ impl Service<Request<Body>> for MetricProvider {
8997 }
9098}
9199
100+ fn is_auth_token_valid ( secret : & str , headers : & HeaderMap < HeaderValue > ) -> bool {
101+ match headers. get ( AUTHORIZATION ) {
102+ Some ( value) => value. to_str ( ) . map_or_else (
103+ |_| false ,
104+ |t| {
105+ if let Some ( t) = t. strip_prefix ( "Bearer " ) {
106+ t == secret
107+ } else {
108+ false
109+ }
110+ } ,
111+ ) ,
112+ None => false ,
113+ }
114+ }
115+
92116pub struct MetricProviderFactory ( pub MetricProvider ) ;
93117
94118impl < T > Service < T > for MetricProviderFactory {
@@ -104,3 +128,40 @@ impl<T> Service<T> for MetricProviderFactory {
104128 future:: ok ( self . 0 . clone ( ) )
105129 }
106130}
131+
132+ #[ cfg( test) ]
133+ mod tests {
134+ use crate :: is_auth_token_valid;
135+ use hyper:: http:: HeaderValue ;
136+ use hyper:: HeaderMap ;
137+
138+ #[ test]
139+ fn auth_token_strip_bearer ( ) {
140+ use hyper:: header:: AUTHORIZATION ;
141+
142+ let secret = "aASgwyfbFAKETOKEN44562uj36" ;
143+ let token = "Bearer aASgwyfbFAKETOKEN44562uj36" ;
144+ let v = HeaderValue :: from_static ( token) ;
145+ let mut hv = HeaderMap :: new ( ) ;
146+ hv. insert ( AUTHORIZATION , v) ;
147+
148+ // should be true
149+ let result = is_auth_token_valid ( secret, & hv) ;
150+ assert ! ( result) ;
151+ }
152+
153+ #[ test]
154+ fn auth_token_strip_bearer_fail ( ) {
155+ use hyper:: header:: AUTHORIZATION ;
156+
157+ let secret = "aASgwyfbFAKETOKEN44562uj36" ;
158+ let token = "Bearer aASgwyfbFAKETOKEN44562uj36 " ; // notice the whitespace in the end
159+ let v = HeaderValue :: from_static ( token) ;
160+ let mut hv = HeaderMap :: new ( ) ;
161+ hv. insert ( AUTHORIZATION , v) ;
162+
163+ // should be true
164+ let result = is_auth_token_valid ( secret, & hv) ;
165+ assert_eq ! ( false , result) ;
166+ }
167+ }
0 commit comments