@@ -84,6 +84,7 @@ impl Config {
84
84
}
85
85
86
86
/// Validate that requests made have a corresponding bearer JWT token
87
+ #[ tracing:: instrument( skip_all, fields( status_code, reason) ) ]
87
88
async fn oauth_validate (
88
89
State ( auth_config) : State < Config > ,
89
90
token : Option < TypedHeader < Authorization < Bearer > > > ,
@@ -104,17 +105,85 @@ async fn oauth_validate(
104
105
} ;
105
106
106
107
let validator = NetworkedTokenValidator :: new ( & auth_config. audiences , & auth_config. servers ) ;
107
- let token = token. ok_or_else ( unauthorized_error) ?;
108
-
109
- let valid_token = validator
110
- . validate ( token. 0 )
111
- . await
112
- . ok_or_else ( unauthorized_error) ?;
108
+ let token = token. ok_or_else ( || {
109
+ tracing:: Span :: current ( ) . record ( "reason" , "missing_token" ) ;
110
+ tracing:: Span :: current ( ) . record ( "status_code" , StatusCode :: UNAUTHORIZED . as_u16 ( ) ) ;
111
+ unauthorized_error ( )
112
+ } ) ?;
113
+
114
+ let valid_token = validator. validate ( token. 0 ) . await . ok_or_else ( || {
115
+ tracing:: Span :: current ( ) . record ( "reason" , "invalid_token" ) ;
116
+ tracing:: Span :: current ( ) . record ( "status_code" , StatusCode :: UNAUTHORIZED . as_u16 ( ) ) ;
117
+ unauthorized_error ( )
118
+ } ) ?;
113
119
114
120
// Insert new context to ensure that handlers only use our enforced token verification
115
121
// for propagation
116
122
request. extensions_mut ( ) . insert ( valid_token) ;
117
123
118
124
let response = next. run ( request) . await ;
125
+ tracing:: Span :: current ( ) . record ( "status_code" , response. status ( ) . as_u16 ( ) ) ;
119
126
Ok ( response)
120
127
}
128
+
129
+ #[ cfg( test) ]
130
+ mod tests {
131
+ use super :: * ;
132
+ use axum:: middleware:: from_fn_with_state;
133
+ use axum:: routing:: get;
134
+ use axum:: {
135
+ Router ,
136
+ body:: Body ,
137
+ http:: { Request , StatusCode } ,
138
+ } ;
139
+ use http:: header:: { AUTHORIZATION , WWW_AUTHENTICATE } ;
140
+ use tower:: ServiceExt ; // for .oneshot()
141
+ use url:: Url ;
142
+
143
+ fn test_config ( ) -> Config {
144
+ Config {
145
+ servers : vec ! [ Url :: parse( "http://localhost:1234" ) . unwrap( ) ] ,
146
+ audiences : vec ! [ "test-audience" . to_string( ) ] ,
147
+ resource : Url :: parse ( "http://localhost:4000" ) . unwrap ( ) ,
148
+ resource_documentation : None ,
149
+ scopes : vec ! [ "read" . to_string( ) ] ,
150
+ disable_auth_token_passthrough : false ,
151
+ }
152
+ }
153
+
154
+ fn test_router ( config : Config ) -> Router {
155
+ Router :: new ( )
156
+ . route ( "/test" , get ( || async { "ok" } ) )
157
+ . layer ( from_fn_with_state ( config, oauth_validate) )
158
+ }
159
+
160
+ #[ tokio:: test]
161
+ async fn missing_token_returns_unauthorized ( ) {
162
+ let config = test_config ( ) ;
163
+ let app = test_router ( config. clone ( ) ) ;
164
+ let req = Request :: builder ( ) . uri ( "/test" ) . body ( Body :: empty ( ) ) . unwrap ( ) ;
165
+ let res = app. oneshot ( req) . await . unwrap ( ) ;
166
+ assert_eq ! ( res. status( ) , StatusCode :: UNAUTHORIZED ) ;
167
+ let headers = res. headers ( ) ;
168
+ let www_auth = headers. get ( WWW_AUTHENTICATE ) . unwrap ( ) . to_str ( ) . unwrap ( ) ;
169
+ assert ! ( www_auth. contains( "Bearer" ) ) ;
170
+ assert ! ( www_auth. contains( "resource_metadata" ) ) ;
171
+ }
172
+
173
+ #[ tokio:: test]
174
+ async fn invalid_token_returns_unauthorized ( ) {
175
+ let config = test_config ( ) ;
176
+ let app = test_router ( config. clone ( ) ) ;
177
+ let req = Request :: builder ( )
178
+ . uri ( "/test" )
179
+ . header ( AUTHORIZATION , "Bearer invalidtoken" )
180
+ . body ( Body :: empty ( ) )
181
+ . unwrap ( ) ;
182
+ let res = app. oneshot ( req) . await . unwrap ( ) ;
183
+ assert_eq ! ( res. status( ) , StatusCode :: UNAUTHORIZED ) ;
184
+ let headers = res. headers ( ) ;
185
+ let www_auth = headers. get ( WWW_AUTHENTICATE ) . unwrap ( ) . to_str ( ) . unwrap ( ) ;
186
+ assert ! ( www_auth. contains( "Bearer" ) ) ;
187
+ assert ! ( www_auth. contains( "resource_metadata" ) ) ;
188
+ }
189
+ }
0 commit comments