1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.directory.api.dsmlv2.engine;
22
23
24 import java.io.BufferedWriter;
25 import java.io.ByteArrayOutputStream;
26 import java.io.File;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.OutputStream;
30 import java.io.OutputStreamWriter;
31 import java.nio.charset.StandardCharsets;
32
33 import org.apache.directory.api.asn1.DecoderException;
34 import org.apache.directory.api.asn1.EncoderException;
35 import org.apache.directory.api.dsmlv2.DsmlDecorator;
36 import org.apache.directory.api.dsmlv2.Dsmlv2Parser;
37 import org.apache.directory.api.dsmlv2.ParserUtils;
38 import org.apache.directory.api.dsmlv2.request.BatchRequestDsml;
39 import org.apache.directory.api.dsmlv2.request.BatchRequestDsml.OnError;
40 import org.apache.directory.api.dsmlv2.request.BatchRequestDsml.Processing;
41 import org.apache.directory.api.dsmlv2.request.BatchRequestDsml.ResponseOrder;
42 import org.apache.directory.api.dsmlv2.request.Dsmlv2Grammar;
43 import org.apache.directory.api.dsmlv2.response.AddResponseDsml;
44 import org.apache.directory.api.dsmlv2.response.BatchResponseDsml;
45 import org.apache.directory.api.dsmlv2.response.BindResponseDsml;
46 import org.apache.directory.api.dsmlv2.response.CompareResponseDsml;
47 import org.apache.directory.api.dsmlv2.response.DelResponseDsml;
48 import org.apache.directory.api.dsmlv2.response.ErrorResponse;
49 import org.apache.directory.api.dsmlv2.response.ErrorResponse.ErrorResponseType;
50 import org.apache.directory.api.dsmlv2.response.ExtendedResponseDsml;
51 import org.apache.directory.api.dsmlv2.response.ModDNResponseDsml;
52 import org.apache.directory.api.dsmlv2.response.ModifyResponseDsml;
53 import org.apache.directory.api.dsmlv2.response.SearchResponseDsml;
54 import org.apache.directory.api.dsmlv2.response.SearchResultDoneDsml;
55 import org.apache.directory.api.dsmlv2.response.SearchResultEntryDsml;
56 import org.apache.directory.api.dsmlv2.response.SearchResultReferenceDsml;
57 import org.apache.directory.api.i18n.I18n;
58 import org.apache.directory.api.ldap.model.cursor.SearchCursor;
59 import org.apache.directory.api.ldap.model.exception.LdapException;
60 import org.apache.directory.api.ldap.model.message.AbandonRequest;
61 import org.apache.directory.api.ldap.model.message.AddRequest;
62 import org.apache.directory.api.ldap.model.message.AddResponse;
63 import org.apache.directory.api.ldap.model.message.BindRequest;
64 import org.apache.directory.api.ldap.model.message.BindRequestImpl;
65 import org.apache.directory.api.ldap.model.message.BindResponse;
66 import org.apache.directory.api.ldap.model.message.CompareRequest;
67 import org.apache.directory.api.ldap.model.message.CompareResponse;
68 import org.apache.directory.api.ldap.model.message.DeleteRequest;
69 import org.apache.directory.api.ldap.model.message.DeleteResponse;
70 import org.apache.directory.api.ldap.model.message.ExtendedRequest;
71 import org.apache.directory.api.ldap.model.message.ExtendedResponse;
72 import org.apache.directory.api.ldap.model.message.MessageTypeEnum;
73 import org.apache.directory.api.ldap.model.message.ModifyDnRequest;
74 import org.apache.directory.api.ldap.model.message.ModifyDnResponse;
75 import org.apache.directory.api.ldap.model.message.ModifyRequest;
76 import org.apache.directory.api.ldap.model.message.ModifyResponse;
77 import org.apache.directory.api.ldap.model.message.Request;
78 import org.apache.directory.api.ldap.model.message.Response;
79 import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
80 import org.apache.directory.api.ldap.model.message.SearchRequest;
81 import org.apache.directory.api.ldap.model.message.SearchResultDone;
82 import org.apache.directory.api.ldap.model.message.SearchResultEntry;
83 import org.apache.directory.api.ldap.model.message.SearchResultReference;
84 import org.apache.directory.api.util.Strings;
85 import org.apache.directory.ldap.client.api.LdapConnection;
86 import org.apache.directory.ldap.client.api.LdapNetworkConnection;
87 import org.dom4j.Element;
88 import org.dom4j.Namespace;
89 import org.slf4j.Logger;
90 import org.slf4j.LoggerFactory;
91 import org.xmlpull.v1.XmlPullParserException;
92
93
94
95
96
97
98
99
100 public class Dsmlv2Engine
101 {
102
103 protected String user;
104
105
106 protected String password;
107
108
109 protected LdapConnection connection;
110
111
112 protected Dsmlv2Parser parser;
113
114
115 protected boolean continueOnError;
116
117
118 protected boolean exit = false;
119
120
121 protected BatchRequestDsml batchRequest;
122
123
124 protected BatchResponseDsml batchResponse = new BatchResponseDsml();
125
126 protected Dsmlv2Grammar grammar = new Dsmlv2Grammar();
127
128
129 protected boolean generateSoapResp = false;
130
131
132 private static final Logger LOG = LoggerFactory.getLogger( Dsmlv2Engine.class );
133
134 private static final String BODY_ENVELOPE = "</Body></Envelope>";
135
136
137
138
139
140
141
142
143
144
145 public Dsmlv2Engine( String host, int port, String user, String password )
146 {
147 this.user = user;
148 this.password = password;
149
150 connection = new LdapNetworkConnection( host, port );
151 }
152
153
154
155
156
157
158
159
160
161 public Dsmlv2Engine( LdapConnection connection, String user, String password )
162 {
163 this.user = user;
164 this.password = password;
165
166 this.connection = connection;
167 }
168
169
170
171
172
173
174
175
176
177 public String processDSML( String dsmlInput ) throws XmlPullParserException
178 {
179 parser = new Dsmlv2Parser( grammar );
180 parser.setInput( dsmlInput );
181
182 return processDSML();
183 }
184
185
186
187
188
189
190
191
192
193
194 public String processDSMLFile( String fileName ) throws XmlPullParserException, IOException
195 {
196 parser = new Dsmlv2Parser( grammar );
197 parser.setInputFile( fileName );
198
199 return processDSML();
200 }
201
202
203
204
205
206
207
208
209
210
211 public void processDSMLFile( File file, OutputStream respStream ) throws Exception
212 {
213 parser = new Dsmlv2Parser( grammar );
214 parser.setInputFile( file.getAbsolutePath() );
215
216 processDSML( respStream );
217 }
218
219
220
221
222
223
224
225
226
227
228 public void processDSML( InputStream inputStream, OutputStream out ) throws Exception
229 {
230 processDSML( inputStream, "UTF-8", out );
231 }
232
233
234
235
236
237
238
239
240
241
242
243 public void processDSML( InputStream inputStream, String inputEncoding, OutputStream out ) throws Exception
244 {
245 parser = new Dsmlv2Parser( grammar );
246 parser.setInput( inputStream, inputEncoding );
247 processDSML( out );
248 }
249
250
251
252
253
254
255
256 private String processDSML()
257 {
258 try
259 {
260 ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
261 processDSML( byteOut );
262 return new String( byteOut.toByteArray(), "UTF-8" );
263 }
264 catch ( IOException e )
265 {
266 LOG.error( "Failed to process the DSML", e );
267 }
268
269 return null;
270 }
271
272
273
274
275
276
277
278
279
280 protected void processDSML( OutputStream outStream ) throws IOException
281 {
282 BufferedWriter respWriter = null;
283
284 if ( outStream != null )
285 {
286 respWriter = new BufferedWriter( new OutputStreamWriter( outStream, StandardCharsets.UTF_8 ) );
287
288 if ( generateSoapResp )
289 {
290 respWriter.write( "<Envelope " );
291
292 Namespace soapNs = new Namespace( null, "http://www.w3.org/2001/12/soap-envelope" );
293 soapNs.write( respWriter );
294
295 respWriter.write( "><Body>" );
296 }
297 }
298
299
300 try
301 {
302 bind( 1 );
303 }
304 catch ( Exception e )
305 {
306 LOG.warn( "Failed to bind", e );
307
308
309
310 ErrorResponse errorResponse = new ErrorResponse( 0, ErrorResponseType.COULD_NOT_CONNECT, e
311 .getLocalizedMessage() );
312
313 batchResponse.addResponse( errorResponse );
314
315 if ( respWriter != null )
316 {
317 respWriter.write( batchResponse.toDsml() );
318 if ( generateSoapResp )
319 {
320 respWriter.write( BODY_ENVELOPE );
321 }
322
323 respWriter.flush();
324 }
325
326 return;
327 }
328
329
330
331
332 try
333 {
334 processBatchRequest();
335 }
336 catch ( XmlPullParserException e )
337 {
338
339 ErrorResponse errorResponse = new ErrorResponse( 0, ErrorResponseType.MALFORMED_REQUEST, I18n.err(
340 I18n.ERR_03001, e.getLocalizedMessage(), e.getLineNumber(), e.getColumnNumber() ) );
341
342 batchResponse.addResponse( errorResponse );
343
344 if ( respWriter != null )
345 {
346 respWriter.write( batchResponse.toDsml() );
347 if ( generateSoapResp )
348 {
349 respWriter.write( BODY_ENVELOPE );
350 }
351
352 respWriter.flush();
353 }
354
355 return;
356 }
357
358 if ( respWriter != null )
359 {
360 StringBuilder sb = new StringBuilder();
361
362 sb.append( "<batchResponse " );
363
364 sb.append( ParserUtils.DSML_NAMESPACE.asXML() );
365
366
367 sb.append( " " );
368
369 sb.append( ParserUtils.XSD_NAMESPACE.asXML() );
370
371
372 sb.append( " " );
373
374 sb.append( ParserUtils.XSI_NAMESPACE.asXML() );
375
376 sb.append( " requestID=\"" );
377 sb.append( batchRequest.getRequestID() );
378 sb.append( "\">" );
379
380 respWriter.write( sb.toString() );
381 }
382
383
384
385
386
387
388
389 DsmlDecorator<? extends Request> request = null;
390
391 try
392 {
393 request = parser.getNextRequest();
394 }
395 catch ( XmlPullParserException e )
396 {
397 LOG.warn( "Failed while getting next request", e );
398
399 int reqId = 0;
400
401
402 ErrorResponse errorResponse = new ErrorResponse( reqId, ErrorResponseType.MALFORMED_REQUEST, I18n.err(
403 I18n.ERR_03001, e.getLocalizedMessage(), e.getLineNumber(), e.getColumnNumber() ) );
404
405 batchResponse.addResponse( errorResponse );
406
407 if ( respWriter != null )
408 {
409 respWriter.write( batchResponse.toDsml() );
410
411 if ( generateSoapResp )
412 {
413 respWriter.write( BODY_ENVELOPE );
414 }
415
416 respWriter.flush();
417 }
418
419 return;
420 }
421
422
423 while ( request != null )
424 {
425
426 if ( ( batchRequest.getProcessing().equals( Processing.PARALLEL ) )
427 && ( batchRequest.getResponseOrder().equals( ResponseOrder.UNORDERED ) )
428 && ( request.getDecorated().getMessageId() <= 0 ) )
429 {
430
431 ErrorResponse errorResponse = new ErrorResponse( 0, ErrorResponseType.MALFORMED_REQUEST, I18n
432 .err( I18n.ERR_03002 ) );
433
434 if ( respWriter != null )
435 {
436 writeResponse( respWriter, errorResponse );
437 }
438 else
439 {
440 batchResponse.addResponse( errorResponse );
441 }
442
443 break;
444 }
445
446 try
447 {
448 processRequest( request, respWriter );
449 }
450 catch ( Exception e )
451 {
452 LOG.warn( "Failed to process request", e );
453
454
455 ErrorResponse errorResponse = new ErrorResponse( request.getDecorated().getMessageId(),
456 ErrorResponseType.GATEWAY_INTERNAL_ERROR, I18n.err(
457 I18n.ERR_03003, e.getMessage() ) );
458
459 if ( respWriter != null )
460 {
461 writeResponse( respWriter, errorResponse );
462 }
463 else
464 {
465 batchResponse.addResponse( errorResponse );
466 }
467
468 break;
469 }
470
471
472 if ( exit )
473 {
474 break;
475 }
476
477
478 try
479 {
480 request = parser.getNextRequest();
481 }
482 catch ( XmlPullParserException e )
483 {
484
485 ErrorResponse errorResponse = new ErrorResponse( 0, ErrorResponseType.MALFORMED_REQUEST, I18n.err(
486 I18n.ERR_03001, e.getLocalizedMessage(), e.getLineNumber(), e.getColumnNumber() ) );
487
488 if ( respWriter != null )
489 {
490 writeResponse( respWriter, errorResponse );
491 }
492 else
493 {
494 batchResponse.addResponse( errorResponse );
495 }
496
497 break;
498 }
499 }
500
501 if ( respWriter != null )
502 {
503 respWriter.write( "</batchResponse>" );
504
505 if ( generateSoapResp )
506 {
507 respWriter.write( BODY_ENVELOPE );
508 }
509
510 respWriter.flush();
511 }
512 }
513
514
515
516
517
518
519
520
521
522 protected void writeResponse( BufferedWriter respWriter, DsmlDecorator<?> respDsml ) throws IOException
523 {
524 if ( respWriter != null )
525 {
526 Element xml = respDsml.toDsml( null );
527 xml.write( respWriter );
528 }
529 }
530
531
532
533
534
535 public boolean isGenerateSoapResp()
536 {
537 return generateSoapResp;
538 }
539
540
541
542
543
544 public void setGenerateSoapResp( boolean generateSoapResp )
545 {
546 this.generateSoapResp = generateSoapResp;
547 }
548
549
550
551
552
553 public BatchResponseDsml getBatchResponse()
554 {
555 return batchResponse;
556 }
557
558
559
560
561
562 public LdapConnection getConnection()
563 {
564 return connection;
565 }
566
567
568
569
570
571
572
573
574
575 protected void processRequest( DsmlDecorator<? extends Request> request, BufferedWriter respWriter )
576 throws Exception
577 {
578 ResultCodeEnum resultCode = null;
579
580 switch ( request.getDecorated().getType() )
581 {
582 case ABANDON_REQUEST:
583 connection.abandon( ( AbandonRequest ) request );
584 return;
585
586 case ADD_REQUEST:
587 AddResponse response = connection.add( ( AddRequest ) request );
588 resultCode = response.getLdapResult().getResultCode();
589 AddResponseDsml addResponseDsml = new AddResponseDsml( connection.getCodecService(), response );
590 writeResponse( respWriter, addResponseDsml );
591
592 break;
593
594 case BIND_REQUEST:
595 BindResponse bindResponse = connection.bind( ( BindRequest ) request );
596 resultCode = bindResponse.getLdapResult().getResultCode();
597 BindResponseDsml authResponseDsml = new BindResponseDsml( connection.getCodecService(), bindResponse );
598 writeResponse( respWriter, authResponseDsml );
599
600 break;
601
602 case COMPARE_REQUEST:
603 CompareResponse compareResponse = connection.compare( ( CompareRequest ) request );
604 resultCode = compareResponse.getLdapResult().getResultCode();
605 CompareResponseDsml compareResponseDsml = new CompareResponseDsml( connection.getCodecService(),
606 compareResponse );
607 writeResponse( respWriter, compareResponseDsml );
608
609 break;
610
611 case DEL_REQUEST:
612 DeleteResponse delResponse = connection.delete( ( DeleteRequest ) request );
613 resultCode = delResponse.getLdapResult().getResultCode();
614 DelResponseDsml delResponseDsml = new DelResponseDsml( connection.getCodecService(), delResponse );
615 writeResponse( respWriter, delResponseDsml );
616
617 break;
618
619 case EXTENDED_REQUEST:
620 ExtendedResponse extendedResponse = connection.extended( ( ExtendedRequest ) request );
621 resultCode = extendedResponse.getLdapResult().getResultCode();
622 ExtendedResponseDsml extendedResponseDsml = new ExtendedResponseDsml( connection.getCodecService(),
623 extendedResponse );
624 writeResponse( respWriter, extendedResponseDsml );
625
626 break;
627
628 case MODIFY_REQUEST:
629 ModifyResponse modifyResponse = connection.modify( ( ModifyRequest ) request );
630 resultCode = modifyResponse.getLdapResult().getResultCode();
631 ModifyResponseDsml modifyResponseDsml = new ModifyResponseDsml( connection.getCodecService(),
632 modifyResponse );
633 writeResponse( respWriter, modifyResponseDsml );
634
635 break;
636
637 case MODIFYDN_REQUEST:
638 ModifyDnResponse modifyDnResponse = connection.modifyDn( ( ModifyDnRequest ) request );
639 resultCode = modifyDnResponse.getLdapResult().getResultCode();
640 ModDNResponseDsml modDNResponseDsml = new ModDNResponseDsml( connection.getCodecService(),
641 modifyDnResponse );
642 writeResponse( respWriter, modDNResponseDsml );
643
644 break;
645
646 case SEARCH_REQUEST:
647 SearchCursor searchResponses = connection.search( ( SearchRequest ) request );
648
649 SearchResponseDsml searchResponseDsml = new SearchResponseDsml( connection.getCodecService() );
650
651 if ( respWriter != null )
652 {
653 StringBuilder sb = new StringBuilder();
654 sb.append( "<searchResponse" );
655
656 if ( request.getDecorated().getMessageId() > 0 )
657 {
658 sb.append( " requestID=\"" );
659 sb.append( request.getDecorated().getMessageId() );
660 sb.append( '"' );
661 }
662
663 sb.append( '>' );
664
665 respWriter.write( sb.toString() );
666 }
667
668 while ( searchResponses.next() )
669 {
670 Response searchResponse = searchResponses.get();
671
672 if ( searchResponse.getType() == MessageTypeEnum.SEARCH_RESULT_ENTRY )
673 {
674 SearchResultEntry searchResultEntry = ( SearchResultEntry ) searchResponse;
675
676 SearchResultEntryDsml searchResultEntryDsml = new SearchResultEntryDsml(
677 connection.getCodecService(), searchResultEntry );
678 searchResponseDsml = new SearchResponseDsml( connection.getCodecService(),
679 searchResultEntryDsml );
680
681 if ( respWriter != null )
682 {
683 writeResponse( respWriter, searchResultEntryDsml );
684 }
685 else
686 {
687 searchResponseDsml.addResponse( searchResultEntryDsml );
688 }
689 }
690 else if ( searchResponse.getType() == MessageTypeEnum.SEARCH_RESULT_REFERENCE )
691 {
692 SearchResultReference searchResultReference = ( SearchResultReference ) searchResponse;
693
694 SearchResultReferenceDsml searchResultReferenceDsml = new SearchResultReferenceDsml(
695 connection.getCodecService(), searchResultReference );
696 searchResponseDsml = new SearchResponseDsml( connection.getCodecService(),
697 searchResultReferenceDsml );
698
699 if ( respWriter != null )
700 {
701 writeResponse( respWriter, searchResultReferenceDsml );
702 }
703 else
704 {
705 searchResponseDsml.addResponse( searchResultReferenceDsml );
706 }
707 }
708 }
709
710 SearchResultDone srDone = searchResponses.getSearchResultDone();
711
712 if ( srDone != null )
713 {
714 resultCode = srDone.getLdapResult().getResultCode();
715
716 SearchResultDoneDsml srdDsml = new SearchResultDoneDsml( connection.getCodecService(), srDone );
717
718 if ( respWriter != null )
719 {
720 writeResponse( respWriter, srdDsml );
721 respWriter.write( "</searchResponse>" );
722 }
723 else
724 {
725 searchResponseDsml.addResponse( srdDsml );
726 batchResponse.addResponse( searchResponseDsml );
727 }
728 }
729
730 break;
731
732 case UNBIND_REQUEST:
733 connection.unBind();
734 break;
735
736 default:
737 throw new IllegalStateException( "Unexpected request tpye " + request.getDecorated().getType() );
738 }
739
740 if ( ( !continueOnError ) && ( resultCode != null ) && ( resultCode != ResultCodeEnum.SUCCESS )
741 && ( resultCode != ResultCodeEnum.COMPARE_TRUE ) && ( resultCode != ResultCodeEnum.COMPARE_FALSE )
742 && ( resultCode != ResultCodeEnum.REFERRAL ) )
743 {
744
745 exit = true;
746 }
747 }
748
749
750
751
752
753
754
755
756
757
758
759 protected void processBatchRequest() throws XmlPullParserException
760 {
761
762 parser.parseBatchRequest();
763
764
765 batchRequest = parser.getBatchRequest();
766
767 if ( OnError.RESUME.equals( batchRequest.getOnError() ) )
768 {
769 continueOnError = true;
770 }
771 else if ( OnError.EXIT.equals( batchRequest.getOnError() ) )
772 {
773 continueOnError = false;
774 }
775
776 if ( ( batchRequest.getRequestID() != 0 ) && ( batchResponse != null ) )
777 {
778 batchResponse.setRequestID( batchRequest.getRequestID() );
779 }
780 }
781
782
783
784
785
786
787
788
789
790
791
792 protected void bind( int messageId ) throws LdapException, EncoderException, DecoderException, IOException
793 {
794 if ( ( connection != null ) && connection.isAuthenticated() )
795 {
796 return;
797 }
798
799 if ( connection == null )
800 {
801 throw new IOException( I18n.err( I18n.ERR_03101_MISSING_CONNECTION_TO ) );
802 }
803
804 BindRequest bindRequest = new BindRequestImpl();
805 bindRequest.setSimple( true );
806 bindRequest.setCredentials( Strings.getBytesUtf8( password ) );
807 bindRequest.setName( user );
808 bindRequest.setVersion3( true );
809 bindRequest.setMessageId( messageId );
810
811 BindResponse bindResponse = connection.bind( bindRequest );
812
813 if ( bindResponse.getLdapResult().getResultCode() != ResultCodeEnum.SUCCESS )
814 {
815 LOG.warn( "Error : {}", bindResponse.getLdapResult().getDiagnosticMessage() );
816 }
817 }
818 }