@@ -84,6 +84,25 @@ pub fn handle_operation(
8484 }
8585 } ;
8686
87+ // Check if filter references undefined attributes
88+ let filter_attributes = ldap_filter. get_referenced_attributes ( ) ;
89+ let existing_attributes = directory. get_all_existing_attributes ( ) ;
90+
91+ for attr in & filter_attributes {
92+ if !existing_attributes. contains ( attr) {
93+ responses. push ( LdapMessage {
94+ message_id,
95+ protocol_op : LdapProtocolOp :: SearchResultDone {
96+ result : LdapResult :: error (
97+ LdapResultCode :: UndefinedAttributeType ,
98+ format ! ( "{}: attribute type undefined" , attr) ,
99+ ) ,
100+ } ,
101+ } ) ;
102+ return responses;
103+ }
104+ }
105+
87106 // Convert scope
88107 let dir_scope = match scope {
89108 SearchScope :: BaseObject => DirSearchScope :: BaseObject ,
@@ -919,4 +938,89 @@ mod tests {
919938 _ => panic ! ( "Expected ExtendedResponse" ) ,
920939 }
921940 }
941+
942+ #[ test]
943+ fn test_search_with_undefined_attribute ( ) {
944+ let directory = create_test_directory ( ) ;
945+ let auth_handler = AuthHandler :: new ( false ) ;
946+
947+ // Search with undefined attribute should return UndefinedAttributeType error
948+ let operation = LdapOperation :: Search {
949+ base_dn : "dc=example,dc=com" . to_string ( ) ,
950+ scope : SearchScope :: WholeSubtree ,
951+ filter : "(userPrincipalName=test)" . to_string ( ) ,
952+ attributes : vec ! [ ] ,
953+ } ;
954+
955+ let responses = handle_operation ( 1 , operation, & directory, & auth_handler, true ) ;
956+
957+ // Should have 1 response: SearchResultDone with error
958+ assert_eq ! ( responses. len( ) , 1 ) ;
959+
960+ match & responses[ 0 ] . protocol_op {
961+ LdapProtocolOp :: SearchResultDone { result } => {
962+ assert_eq ! ( result. result_code, LdapResultCode :: UndefinedAttributeType ) ;
963+ assert ! ( result
964+ . diagnostic_message
965+ . contains( "attribute type undefined" ) ) ;
966+ }
967+ _ => panic ! ( "Expected SearchResultDone" ) ,
968+ }
969+ }
970+
971+ #[ test]
972+ fn test_search_with_undefined_attribute_in_complex_filter ( ) {
973+ let directory = create_test_directory ( ) ;
974+ let auth_handler = AuthHandler :: new ( false ) ;
975+
976+ // AND filter with undefined attribute
977+ let operation = LdapOperation :: Search {
978+ base_dn : "dc=example,dc=com" . to_string ( ) ,
979+ scope : SearchScope :: WholeSubtree ,
980+ filter : "(&(uid=user1)(nonExistentAttr=value))" . to_string ( ) ,
981+ attributes : vec ! [ ] ,
982+ } ;
983+
984+ let responses = handle_operation ( 1 , operation, & directory, & auth_handler, true ) ;
985+
986+ // Should have 1 response: SearchResultDone with error
987+ assert_eq ! ( responses. len( ) , 1 ) ;
988+
989+ match & responses[ 0 ] . protocol_op {
990+ LdapProtocolOp :: SearchResultDone { result } => {
991+ assert_eq ! ( result. result_code, LdapResultCode :: UndefinedAttributeType ) ;
992+ assert ! ( result. diagnostic_message. contains( "nonexistentattr" ) ) ;
993+ assert ! ( result
994+ . diagnostic_message
995+ . contains( "attribute type undefined" ) ) ;
996+ }
997+ _ => panic ! ( "Expected SearchResultDone" ) ,
998+ }
999+ }
1000+
1001+ #[ test]
1002+ fn test_search_with_valid_attributes_still_works ( ) {
1003+ let directory = create_test_directory ( ) ;
1004+ let auth_handler = AuthHandler :: new ( false ) ;
1005+
1006+ // Search with valid attribute should work
1007+ let operation = LdapOperation :: Search {
1008+ base_dn : "dc=example,dc=com" . to_string ( ) ,
1009+ scope : SearchScope :: WholeSubtree ,
1010+ filter : "(uid=user1)" . to_string ( ) ,
1011+ attributes : vec ! [ ] ,
1012+ } ;
1013+
1014+ let responses = handle_operation ( 1 , operation, & directory, & auth_handler, true ) ;
1015+
1016+ // Should have 2 responses: 1 entry + done
1017+ assert_eq ! ( responses. len( ) , 2 ) ;
1018+
1019+ match & responses[ 1 ] . protocol_op {
1020+ LdapProtocolOp :: SearchResultDone { result } => {
1021+ assert_eq ! ( result. result_code, LdapResultCode :: Success ) ;
1022+ }
1023+ _ => panic ! ( "Expected SearchResultDone" ) ,
1024+ }
1025+ }
9221026}
0 commit comments