@@ -22,16 +22,46 @@ use std::future::{ready, Ready};
22
22
use actix_web:: {
23
23
dev:: { forward_ready, Service , ServiceRequest , ServiceResponse , Transform } ,
24
24
error:: { ErrorBadRequest , ErrorUnauthorized } ,
25
- Error ,
25
+ Error , Route ,
26
26
} ;
27
27
use actix_web_httpauth:: extractors:: basic:: BasicAuth ;
28
28
use futures_util:: future:: LocalBoxFuture ;
29
29
30
30
use crate :: { option:: CONFIG , rbac:: role:: Action , rbac:: Users } ;
31
31
32
+ pub trait RouteExt {
33
+ fn authorize ( self , action : Action ) -> Self ;
34
+ fn authorize_for_stream ( self , action : Action ) -> Self ;
35
+ fn authorize_for_user ( self , action : Action ) -> Self ;
36
+ }
37
+
38
+ impl RouteExt for Route {
39
+ fn authorize ( self , action : Action ) -> Self {
40
+ self . wrap ( Auth {
41
+ action,
42
+ method : auth_no_context,
43
+ } )
44
+ }
45
+
46
+ fn authorize_for_stream ( self , action : Action ) -> Self {
47
+ self . wrap ( Auth {
48
+ action,
49
+ method : auth_stream_context,
50
+ } )
51
+ }
52
+
53
+ fn authorize_for_user ( self , action : Action ) -> Self {
54
+ self . wrap ( Auth {
55
+ action,
56
+ method : auth_user_context,
57
+ } )
58
+ }
59
+ }
60
+
61
+ // Authentication Layer with no context
32
62
pub struct Auth {
33
63
pub action : Action ,
34
- pub stream : bool ,
64
+ pub method : fn ( & mut ServiceRequest , Action ) -> Result < bool , Error > ,
35
65
}
36
66
37
67
impl < S , B > Transform < S , ServiceRequest > for Auth
@@ -49,15 +79,15 @@ where
49
79
fn new_transform ( & self , service : S ) -> Self :: Future {
50
80
ready ( Ok ( AuthMiddleware {
51
81
action : self . action ,
52
- match_stream : self . stream ,
53
82
service,
83
+ auth_method : self . method ,
54
84
} ) )
55
85
}
56
86
}
57
87
58
88
pub struct AuthMiddleware < S > {
59
89
action : Action ,
60
- match_stream : bool ,
90
+ auth_method : fn ( & mut ServiceRequest , Action ) -> Result < bool , Error > ,
61
91
service : S ,
62
92
}
63
93
@@ -74,38 +104,46 @@ where
74
104
forward_ready ! ( service) ;
75
105
76
106
fn call ( & self , mut req : ServiceRequest ) -> Self :: Future {
77
- // Extract username and password from the request using basic auth extractor.
78
- let creds = req. extract :: < BasicAuth > ( ) . into_inner ( ) ;
79
- let creds = creds. map_err ( Into :: into) . map ( |creds| {
80
- let username = creds. user_id ( ) . trim ( ) . to_owned ( ) ;
81
- // password is not mandatory by basic auth standard.
82
- // If not provided then treat as empty string
83
- let password = creds. password ( ) . unwrap_or ( "" ) . trim ( ) . to_owned ( ) ;
84
- ( username, password)
85
- } ) ;
86
-
87
- let stream = if self . match_stream {
88
- req. match_info ( ) . get ( "logstream" )
89
- } else {
90
- None
91
- } ;
92
-
93
- let auth_result: Result < bool , Error > = creds. map ( |( username, password) | {
94
- Users . authenticate ( username, password, self . action , stream)
95
- } ) ;
96
-
107
+ let auth_result: Result < bool , Error > = ( self . auth_method ) ( & mut req, self . action ) ;
97
108
let fut = self . service . call ( req) ;
98
-
99
109
Box :: pin ( async move {
100
110
if !auth_result? {
101
111
return Err ( ErrorUnauthorized ( "Not authorized" ) ) ;
102
112
}
103
-
104
113
fut. await
105
114
} )
106
115
}
107
116
}
108
117
118
+ pub fn auth_no_context ( req : & mut ServiceRequest , action : Action ) -> Result < bool , Error > {
119
+ let creds = extract_basic_auth ( req) ;
120
+ creds. map ( |( username, password) | Users . authenticate ( username, password, action, None , None ) )
121
+ }
122
+
123
+ pub fn auth_stream_context ( req : & mut ServiceRequest , action : Action ) -> Result < bool , Error > {
124
+ let creds = extract_basic_auth ( req) ;
125
+ let stream = req. match_info ( ) . get ( "logstream" ) ;
126
+ creds. map ( |( username, password) | Users . authenticate ( username, password, action, stream, None ) )
127
+ }
128
+
129
+ pub fn auth_user_context ( req : & mut ServiceRequest , action : Action ) -> Result < bool , Error > {
130
+ let creds = extract_basic_auth ( req) ;
131
+ let user = req. match_info ( ) . get ( "username" ) ;
132
+ creds. map ( |( username, password) | Users . authenticate ( username, password, action, None , user) )
133
+ }
134
+
135
+ fn extract_basic_auth ( req : & mut ServiceRequest ) -> Result < ( String , String ) , Error > {
136
+ // Extract username and password from the request using basic auth extractor.
137
+ let creds = req. extract :: < BasicAuth > ( ) . into_inner ( ) ;
138
+ creds. map_err ( Into :: into) . map ( |creds| {
139
+ let username = creds. user_id ( ) . trim ( ) . to_owned ( ) ;
140
+ // password is not mandatory by basic auth standard.
141
+ // If not provided then treat as empty string
142
+ let password = creds. password ( ) . unwrap_or ( "" ) . trim ( ) . to_owned ( ) ;
143
+ ( username, password)
144
+ } )
145
+ }
146
+
109
147
// The credentials set in the env vars (P_USERNAME & P_PASSWORD) are treated
110
148
// as root credentials. Any other user is not allowed to modify or delete
111
149
// the root user. Deny request if username is same as username
0 commit comments