1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.api.ldap.codec.api;
21
22
23 import javax.security.sasl.Sasl;
24 import javax.security.sasl.SaslClient;
25 import javax.security.sasl.SaslException;
26 import javax.security.sasl.SaslServer;
27
28 import org.apache.directory.api.ldap.model.constants.SaslQoP;
29 import org.apache.mina.core.buffer.IoBuffer;
30 import org.apache.mina.core.filterchain.IoFilterAdapter;
31 import org.apache.mina.core.session.IoSession;
32 import org.apache.mina.core.write.DefaultWriteRequest;
33 import org.apache.mina.core.write.WriteRequest;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37
38
39
40
41
42
43
44
45
46
47
48 public class SaslFilter extends IoFilterAdapter
49 {
50 private static final Logger LOG = LoggerFactory.getLogger( SaslFilter.class );
51
52
53
54
55
56
57
58
59
60
61 public static final String DISABLE_SECURITY_LAYER_ONCE = SaslFilter.class.getName() + ".DisableSecurityLayerOnce";
62
63
64
65
66
67 public static final String BYTES = SaslFilter.class.getName() + ".Buffer";
68
69
70
71
72
73 public static final String OFFSET = SaslFilter.class.getName() + ".Offset";
74
75
76 private final SaslClient saslClient;
77
78
79 private final SaslServer saslServer;
80
81
82 private boolean hasSecurityLayer;
83
84
85 private int maxBufferSize;
86
87
88
89
90
91
92
93
94
95 public SaslFilter( SaslClient saslClient )
96 {
97 if ( saslClient == null )
98 {
99 throw new IllegalArgumentException();
100 }
101
102 this.saslServer = null;
103 this.saslClient = saslClient;
104 initHasSecurityLayer( ( String ) saslClient.getNegotiatedProperty( Sasl.QOP ) );
105 initMaxBuffer( ( String ) saslClient.getNegotiatedProperty( Sasl.MAX_BUFFER ) );
106 }
107
108
109
110
111
112
113
114
115
116
117 public SaslFilter( SaslServer saslServer )
118 {
119 if ( saslServer == null )
120 {
121 throw new IllegalArgumentException();
122 }
123
124 this.saslClient = null;
125 this.saslServer = saslServer;
126 initHasSecurityLayer( ( String ) saslServer.getNegotiatedProperty( Sasl.QOP ) );
127 initMaxBuffer( ( String ) saslServer.getNegotiatedProperty( Sasl.MAX_BUFFER ) );
128 }
129
130
131 private void initHasSecurityLayer( String qop )
132 {
133 this.hasSecurityLayer = ( qop != null && ( qop.equals( SaslQoP.AUTH_INT.getValue() ) || qop
134 .equals( SaslQoP.AUTH_CONF.getValue() ) ) );
135 }
136
137
138 private void initMaxBuffer( String maxBuffer )
139 {
140 this.maxBufferSize = maxBuffer != null ? Integer.parseInt( maxBuffer ) : 65536;
141 }
142
143
144 @Override
145 public synchronized void messageReceived( NextFilter nextFilter, IoSession session, Object message )
146 throws SaslException
147 {
148 LOG.debug( "Message received: {}", message );
149
150 if ( !hasSecurityLayer )
151 {
152 LOG.debug( "Will not use SASL on received message." );
153 nextFilter.messageReceived( session, message );
154 return;
155 }
156
157
158
159
160 IoBuffer buf = ( IoBuffer ) message;
161 while ( buf.hasRemaining() )
162 {
163
164
165
166
167
168 byte[] bytes = ( byte[] ) session.getAttribute( BYTES, null );
169 int offset = ( int ) session.getAttribute( OFFSET, -1 );
170 if ( bytes == null )
171 {
172 int bufferSize = buf.getInt();
173 if ( bufferSize > maxBufferSize )
174 {
175 throw new IllegalStateException(
176 bufferSize + " exceeds the negotiated receive buffer size limit: " + maxBufferSize );
177 }
178 bytes = new byte[bufferSize];
179 offset = 0;
180 }
181
182
183
184
185 int length = Math.min( bytes.length - offset, buf.remaining() );
186 buf.get( bytes, offset, length );
187
188
189
190
191
192 offset += length;
193 if ( offset < bytes.length )
194 {
195 LOG.debug( "Partial SASL message received: {}/{}", offset, bytes.length );
196 session.setAttribute( BYTES, bytes );
197 session.setAttribute( OFFSET, offset );
198 break;
199 }
200
201
202
203
204 LOG.debug( "Will use SASL to unwrap received message of length: {}", bytes.length );
205 byte[] token = unwrap( bytes, 0, bytes.length );
206 nextFilter.messageReceived( session, IoBuffer.wrap( token ) );
207
208
209
210
211 session.removeAttribute( BYTES );
212 session.removeAttribute( OFFSET );
213 }
214 }
215
216
217 @Override
218 public synchronized void filterWrite( NextFilter nextFilter, IoSession session, WriteRequest writeRequest )
219 throws SaslException
220 {
221 LOG.debug( "Filtering write request: {}", writeRequest );
222
223
224
225
226 if ( session.containsAttribute( DISABLE_SECURITY_LAYER_ONCE ) )
227 {
228
229 LOG.debug( "Disabling SaslFilter once; will not use SASL on write request." );
230 session.removeAttribute( DISABLE_SECURITY_LAYER_ONCE );
231 nextFilter.filterWrite( session, writeRequest );
232 return;
233 }
234
235 if ( !hasSecurityLayer )
236 {
237 LOG.debug( "Will not use SASL on write request." );
238 nextFilter.filterWrite( session, writeRequest );
239 return;
240 }
241
242
243
244
245
246
247
248
249 IoBuffer buf = ( IoBuffer ) writeRequest.getMessage();
250 int bufferLength = buf.remaining();
251 byte[] bufferBytes = new byte[bufferLength];
252 buf.get( bufferBytes );
253
254 LOG.info( "Will use SASL to wrap message of length: {}", bufferLength );
255
256
257
258
259 int max = maxBufferSize - 200;
260 for ( int offset = 0; offset < bufferLength; offset += max )
261 {
262 int length = Math.min( bufferLength - offset, max );
263 byte[] saslLayer = wrap( bufferBytes, offset, length );
264
265
266
267
268 IoBuffer saslLayerBuffer = IoBuffer.allocate( 4 + saslLayer.length );
269 saslLayerBuffer.putInt( saslLayer.length );
270 saslLayerBuffer.put( saslLayer );
271 saslLayerBuffer.position( 0 );
272 saslLayerBuffer.limit( 4 + saslLayer.length );
273
274 LOG.debug( "Sending encrypted token of length {}.", saslLayerBuffer.limit() );
275 nextFilter.filterWrite( session, new DefaultWriteRequest( saslLayerBuffer, writeRequest.getFuture() ) );
276 }
277 }
278
279
280 private byte[] wrap( byte[] buffer, int offset, int length ) throws SaslException
281 {
282 if ( saslClient != null )
283 {
284 return saslClient.wrap( buffer, offset, length );
285 }
286 else
287 {
288 return saslServer.wrap( buffer, offset, length );
289 }
290 }
291
292
293 private byte[] unwrap( byte[] buffer, int offset, int length ) throws SaslException
294 {
295 if ( saslClient != null )
296 {
297 return saslClient.unwrap( buffer, offset, length );
298 }
299 else
300 {
301 return saslServer.unwrap( buffer, offset, length );
302 }
303 }
304
305 }