Browse Source
			 
			
			Allow Authorization header for Web Sockets 
 
Some clients (Thirdparty) might use the `Authorization` header instead
of a query param. We didn't supported this since all the official
clients do not seem to use this way of working. But Bitwarden does check
both ways.
This PR adds an extra check for this header which can be optional.
Fixes  #3776  
			
			
				 
		
			
				
					
						BlackDex 
					
					2 years ago  
				
			 
		 
		
			
				
					GPG Key ID:  
		
		
		
	
		
			
				 2 changed files  with 
33 additions  and 
2 deletions 
			 
			
		 
		
			
				
					
					
					  
					src/api/notifications.rs 
				 
			
				
					
					
					  
					src/auth.rs 
				 
			
		 
		
			
			
			
			
			
			
				
				
					
						
							
								
									
	
		
			
				
					
						
						
							
								 
						
						
					 
				
				@ -20,7 +20,7 @@ use tokio_tungstenite::{ 
			
		
	
		
			
				
					} ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					use   crate ::{  
			
		
	
		
			
				
					     auth ::ClientIp ,  
			
		
	
		
			
				
					     auth ::{ ClientIp ,   WsAccessTokenHeader } ,  
			
		
	
		
			
				
					     db ::{  
			
		
	
		
			
				
					         models ::{ Cipher ,   Folder ,   Send   as   DbSend ,   User } ,  
			
		
	
		
			
				
					         DbConn ,  
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -111,11 +111,19 @@ fn websockets_hub<'r>( 
			
		
	
		
			
				
					     ws : rocket_ws ::WebSocket ,  
			
		
	
		
			
				
					     data : WsAccessToken ,  
			
		
	
		
			
				
					     ip : ClientIp ,  
			
		
	
		
			
				
					     header_token : WsAccessTokenHeader ,  
			
		
	
		
			
				
					)   -> Result < rocket_ws ::Stream ! [ 'r ] ,   Error >   {  
			
		
	
		
			
				
					     let   addr   =   ip . ip ;  
			
		
	
		
			
				
					     info ! ( "Accepting Rocket WS connection from {addr}" ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     let   Some ( token )   =   data . access_token   else   {   err_code ! ( "Invalid claim" ,   401 )   } ;  
			
		
	
		
			
				
					     let   token   =   if   let   Some ( token )   =   data . access_token   {  
			
		
	
		
			
				
					         token  
			
		
	
		
			
				
					     }   else   if   let   Some ( token )   =   header_token . access_token   {  
			
		
	
		
			
				
					         token  
			
		
	
		
			
				
					     }   else   {  
			
		
	
		
			
				
					         err_code ! ( "Invalid claim" ,   401 )  
			
		
	
		
			
				
					     } ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     let   Ok ( claims )   =   crate ::auth ::decode_login ( & token )   else   {   err_code ! ( "Invalid token" ,   401 )   } ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     let   ( mut   rx ,   guard )   =   {  
			
		
	
	
		
			
				
					
						
							
								 
						
						
						
					 
				
				 
			
		
	
								
							
						
					 
					
				 
			 
		
			
			
			
			
			
			
				
				
					
						
							
								
									
	
		
			
				
					
						
						
							
								 
						
						
					 
				
				@ -825,3 +825,26 @@ impl<'r> FromRequest<'r> for ClientIp { 
			
		
	
		
			
				
					         } )  
			
		
	
		
			
				
					     }  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					pub   struct  WsAccessTokenHeader   {  
			
		
	
		
			
				
					     pub   access_token : Option < String > ,  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ rocket::async_trait ]  
			
		
	
		
			
				
					impl < 'r >   FromRequest < 'r >   for   WsAccessTokenHeader   {  
			
		
	
		
			
				
					     type  Error   =   ( ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     async   fn  from_request ( request : & 'r   Request < '_ > )   -> Outcome < Self ,   Self ::Error >   {  
			
		
	
		
			
				
					         let   headers   =   request . headers ( ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					         // Get access_token
  
			
		
	
		
			
				
					         let   access_token   =   match   headers . get_one ( "Authorization" )   {  
			
		
	
		
			
				
					             Some ( a )   = >   a . rsplit ( "Bearer " ) . next ( ) . map ( String ::from ) ,  
			
		
	
		
			
				
					             None   = >   None ,  
			
		
	
		
			
				
					         } ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					         Outcome ::Success ( Self   {  
			
		
	
		
			
				
					             access_token ,  
			
		
	
		
			
				
					         } )  
			
		
	
		
			
				
					     }  
			
		
	
		
			
				
					}