~ubuntu-branches/ubuntu/maverick/eucalyptus/maverick

« back to all changes in this revision

Viewing changes to clc/modules/wsstack/src/main/java/com/eucalyptus/ws/handlers/WalrusPOSTAuthenticationHandler.java

  • Committer: Bazaar Package Importer
  • Author(s): Dave Walker (Daviey)
  • Date: 2010-07-21 17:27:10 UTC
  • mfrom: (1.1.38 upstream)
  • Revision ID: james.westby@ubuntu.com-20100721172710-7xv07dmdqgivc3t9
Tags: 2.0~bzr1211-0ubuntu1
* New major upstream version merge, 2.0 (r1211).
* debian/patches/:
  - 01-wsdl-stubs.patch, debian/wsdl.md5sums: wsdl stubs updated.
  - 02-Makefile.patch: Updated to reflect new code layout.
  - 07-local_support_euca_conf-in.patch: Updated to reflect new code layout.
  - 08-ubuntu-default-networking.patch: Refreshed.
  - 09-small-128-192MB.patch: Updated to point to new location.
  - 10-disable-iscsi.patch: Refreshed.
  - 11-state-cleanup-memleakfix.patch: Removed, fixed upstream.
  - 15-fix-default-ramdisk.patch: Updated to point to new location.
  - 16-kvm_libvirt_xml_default_use_kvm.patch: Updated to reflect changes.
  - 17-fix_walrus_OOM_errors.patch: Removed, fixed upstream.
  - 18-priv_security.patch: Updated to reflect upstream changes.
  - 20-brute-force-webui.patch: Updated to reflect upstream changes. 
  - 21-eucalyptus-1.7-with-gwt-1.6.4.patch: New patch, allows 
    eucalyptus-1.7 to be built against gwt 1.6.4. Based on patch courtesy 
    of Dmitrii Zagorodnov, upstream. (LP: #597330)
* debian/eucalyptus-java-common.links: 
  - Changed symlink for groovy, point to groovy.all.jar, making compatiable 
    with groovy versions >1.7. (LP: #595421)
  - Added ant.jar & jetty-rewrite-handler.jar as they are now required.
* debian/control
  - & debian/build-jars: Added libjavassist-java and libjetty-extra-java as 
    build dependencies.
  - Added libjetty-extra-java as a dependency of eucalyptus-java-common
* The binary resulting jar's have been renamed from eucalyptus-*-1.6.2.jar
  to eucalyptus-*-main.jar:    
  - debian/eucalyptus-cc.upstart
  - debian/eucalyptus-cloud.install
  - debian/eucalyptus-common.eucalyptus.upstart
  - debian/eucalyptus-java-common.install
  - debian/eucalyptus-network.upstart
  - debian/eucalyptus-sc.install
  - debian/eucalyptus-walrus.install
* debian/eucalyptus-java-common.install: New upstream jars that have been
  installed:
  - eucalyptus-db-hsqldb-ext-main.jar
  - eucalyptus-component-main.jar
* debian/control:
  - Updated Standards Version to 3.8.4 (no change)
  - Updated the upstream Homepage to: http://open.eucalyptus.com/
  - Changed Vcs-Bzr to reflect new location of Ubuntu hosted development branch.
  - Made the Build Dependency of groovy and the binary eucalyptus-java-common
    package depend on version >=1.7.

Show diffs side-by-side

added added

removed removed

Lines of Context:
60
60
 *******************************************************************************/
61
61
package com.eucalyptus.ws.handlers;
62
62
 
63
 
import java.io.ByteArrayInputStream;
64
63
import java.util.ArrayList;
65
64
import java.util.Date;
66
65
import java.util.HashMap;
67
 
import java.util.InputMismatchException;
68
66
import java.util.Iterator;
69
67
import java.util.List;
70
68
import java.util.Map;
71
 
import java.util.Scanner;
72
69
import java.util.Set;
73
70
 
74
71
import javax.crypto.Mac;
98
95
import org.jboss.netty.handler.codec.http.HttpVersion;
99
96
 
100
97
import com.eucalyptus.auth.NoSuchUserException;
101
 
import com.eucalyptus.auth.User;
102
 
import com.eucalyptus.auth.CredentialProvider;
 
98
import com.eucalyptus.auth.Users;
 
99
import com.eucalyptus.auth.crypto.Hmac;
 
100
import com.eucalyptus.auth.login.AuthenticationException;
 
101
import com.eucalyptus.auth.principal.User;
103
102
import com.eucalyptus.auth.util.Hashes;
 
103
import com.eucalyptus.context.Context;
 
104
import com.eucalyptus.context.Contexts;
 
105
import com.eucalyptus.http.MappingHttpRequest;
104
106
import com.eucalyptus.util.WalrusProperties;
105
 
import com.eucalyptus.ws.AuthenticationException;
106
 
import com.eucalyptus.ws.MappingHttpRequest;
 
107
import com.eucalyptus.util.WalrusUtil;
107
108
 
108
109
@ChannelPipelineCoverage("one")
109
110
public class WalrusPOSTAuthenticationHandler extends MessageStackHandler {
141
142
                        Map formFields = httpRequest.getFormFields();
142
143
                        String boundary = processPOSTHeaders(httpRequest, formFields);
143
144
                        processPOSTParams(boundary, formFields, httpRequest.getContent());
144
 
                        checkPolicy(httpRequest, formFields);
 
145
                        UploadPolicyChecker.checkPolicy(httpRequest, formFields);
145
146
                        handle(httpRequest);
146
147
                } else if(event.getMessage() instanceof DefaultHttpChunk) {
147
148
                        DefaultHttpChunk httpChunk = (DefaultHttpChunk) event.getMessage();
148
 
                        //if(httpChunk.isLast()) {
149
149
                        ChannelBuffer newBuffer = getDataChunk(httpChunk.getContent(), boundary);
150
150
                        if(newBuffer != null) {
151
151
                                DefaultHttpChunk newChunk = new DefaultHttpChunk(newBuffer);
160
160
                if(httpRequest.getFormFields().size() > 0) {
161
161
                        String data = httpRequest.getAndRemoveHeader(WalrusProperties.FormField.FormUploadPolicyData.toString());
162
162
                        String auth_part = httpRequest.getAndRemoveHeader(SecurityParameter.Authorization.toString());
163
 
                        /*try {
164
 
                                User user = CredentialProvider.getUser( "admin" );
165
 
                                user.setIsAdministrator(true);
166
 
                                httpRequest.setUser( user );
167
 
                        } catch (NoSuchUserException e) {
168
 
                                throw new AuthenticationException( "User authentication failed." );
169
 
                        } */
170
163
                        if(auth_part != null) {
171
164
                                String sigString[] = getSigInfo(auth_part);
172
165
                                String signature = sigString[1];                                
182
175
        private void authenticate(MappingHttpRequest httpRequest, String accessKeyID, String signature, String data) throws AuthenticationException {
183
176
                signature = signature.replaceAll("=", "");
184
177
                try {
185
 
                        String queryKey = CredentialProvider.getSecretKey(accessKeyID);
 
178
      User user = Users.lookupQueryId( accessKeyID );  
 
179
      String queryKey = user.getSecretKey( );
186
180
                        String authSig = checkSignature( queryKey, data );
187
181
                        if (!authSig.equals(signature))
188
182
                                throw new AuthenticationException( "User authentication failed. Could not verify signature" );
189
 
                        String userName = CredentialProvider.getUserName( accessKeyID );
190
 
                        User user = CredentialProvider.getUser(userName);  
191
 
                        httpRequest.setUser( user );
 
183
      Contexts.lookup( httpRequest.getCorrelationId( ) ).setUser( user );
192
184
                } catch(Exception ex) {
193
185
                        throw new AuthenticationException( "User authentication failed. Unable to obtain query key" );
194
186
                }
202
194
 
203
195
        protected String checkSignature( final String queryKey, final String subject ) throws AuthenticationException
204
196
        {
205
 
                SecretKeySpec signingKey = new SecretKeySpec( queryKey.getBytes(), Hashes.Mac.HmacSHA1.toString() );
 
197
                SecretKeySpec signingKey = new SecretKeySpec( queryKey.getBytes(), Hmac.HmacSHA1.toString() );
206
198
                try
207
199
                {
208
 
                        Mac mac = Mac.getInstance( Hashes.Mac.HmacSHA1.toString() );
 
200
                        Mac mac = Hmac.HmacSHA1.getInstance( );
209
201
                        mac.init( signingKey );
210
202
                        byte[] rawHmac = mac.doFinal( subject.getBytes() );
211
203
                        return new String(Base64.encode( rawHmac )).replaceAll( "=", "" );
226
218
                                boundary = "--" + boundary + "\r\n";
227
219
                                this.boundary = boundary;
228
220
                        }
229
 
                        String[] target = getTarget(httpRequest);
 
221
                        String operationPath = httpRequest.getServicePath().replaceAll(WalrusProperties.walrusServicePath, "");
 
222
                        String[] target = WalrusUtil.getTarget(operationPath);
230
223
                        formFields.put(WalrusProperties.FormField.bucket.toString(), target[0]);
231
224
                        return boundary;
232
225
                } else {
252
245
                }
253
246
        }
254
247
 
255
 
        private void checkPolicy(MappingHttpRequest httpRequest, Map<String, String> formFields) throws AuthenticationException {
256
 
                if(formFields.containsKey(WalrusProperties.FormField.policy.toString())) {
257
 
                        String authenticationHeader = "";
258
 
                        String policy = new String(Base64.decode(formFields.remove(WalrusProperties.FormField.policy.toString())));
259
 
                        String policyData;
260
 
                        try {
261
 
                                policyData = new String(Base64.encode(policy.getBytes()));
262
 
                        } catch (Exception ex) {
263
 
                                LOG.warn(ex, ex);
264
 
                                throw new AuthenticationException("error reading policy data.");
265
 
                        }
266
 
                        //parse policy
267
 
                        try {
268
 
                                JsonSlurper jsonSlurper = new JsonSlurper();
269
 
                                JSONObject policyObject = (JSONObject)jsonSlurper.parseText(policy);
270
 
                                String expiration = (String) policyObject.get(WalrusProperties.PolicyHeaders.expiration.toString());
271
 
                                if(expiration != null) {
272
 
                                        Date expirationDate = DateUtils.parseIso8601DateTimeOrDate(expiration);
273
 
                                        if((new Date()).getTime() > expirationDate.getTime()) {
274
 
                                                LOG.warn("Policy has expired.");
275
 
                                                throw new AuthenticationException("Policy has expired.");
276
 
                                        }
277
 
                                }
278
 
                                List<String> policyItemNames = new ArrayList<String>();
279
 
 
280
 
                                JSONArray conditions = (JSONArray) policyObject.get(WalrusProperties.PolicyHeaders.conditions.toString());
281
 
                                for (int i = 0 ; i < conditions.size() ; ++i) {
282
 
                                        Object policyItem = conditions.get(i);
283
 
                                        if(policyItem instanceof JSONObject) {
284
 
                                                JSONObject jsonObject = (JSONObject) policyItem;
285
 
                                                if(!exactMatch(jsonObject, formFields, policyItemNames)) {
286
 
                                                        LOG.warn("Policy verification failed. ");
287
 
                                                        throw new AuthenticationException("Policy verification failed.");
288
 
                                                }
289
 
                                        } else if(policyItem instanceof  JSONArray) {
290
 
                                                JSONArray jsonArray = (JSONArray) policyItem;
291
 
                                                if(!partialMatch(jsonArray, formFields, policyItemNames)) {
292
 
                                                        LOG.warn("Policy verification failed. ");
293
 
                                                        throw new AuthenticationException("Policy verification failed.");
294
 
                                                }
295
 
                                        }
296
 
                                }
297
 
 
298
 
                                Set<String> formFieldsKeys = formFields.keySet();
299
 
                                for(String formKey : formFieldsKeys) {
300
 
                                        if(formKey.startsWith(WalrusProperties.IGNORE_PREFIX))
301
 
                                                continue;
302
 
                                        boolean fieldOkay = false;
303
 
                                        for(WalrusProperties.IgnoredFields field : WalrusProperties.IgnoredFields.values()) {
304
 
                                                if(formKey.equals(field.toString())) {
305
 
                                                        fieldOkay = true;
306
 
                                                        break;
307
 
                                                }
308
 
                                        }
309
 
                                        if(fieldOkay)
310
 
                                                continue;
311
 
                                        if(policyItemNames.contains(formKey))
312
 
                                                continue;
313
 
                                        LOG.warn("All fields except those marked with x-ignore- should be in policy.");
314
 
                                        throw new AuthenticationException("All fields except those marked with x-ignore- should be in policy.");
315
 
                                }
316
 
                        } catch(Exception ex) {
317
 
                                //rethrow
318
 
                                LOG.warn(ex);
319
 
                                if(ex instanceof AuthenticationException)
320
 
                                        throw (AuthenticationException)ex;
321
 
                        }
322
 
                        //all form uploads without a policy are anonymous
323
 
                        if(formFields.containsKey(WalrusProperties.FormField.AWSAccessKeyId.toString())) {
324
 
                                String accessKeyId = formFields.remove(WalrusProperties.FormField.AWSAccessKeyId.toString());
325
 
                                authenticationHeader += "AWS" + " " + accessKeyId + ":";
326
 
                        }
327
 
                        if(formFields.containsKey(WalrusProperties.FormField.signature.toString())) {
328
 
                                String signature = formFields.remove(WalrusProperties.FormField.signature.toString());
329
 
                                authenticationHeader += signature;
330
 
                                httpRequest.addHeader(WalrusPOSTAuthenticationHandler.SecurityParameter.Authorization.toString(), authenticationHeader);
331
 
                        }
332
 
                        httpRequest.addHeader(WalrusProperties.FormField.FormUploadPolicyData.toString(), policyData);
333
 
                }
334
 
        }
335
248
 
336
249
        private Map<String, String> getFormField(String message, String key) {
337
250
                Map<String, String> keymap = new HashMap<String, String>();
465
378
                return lastIndex;
466
379
        }
467
380
 
468
 
        private boolean exactMatch(JSONObject jsonObject, Map<String, String> formFields, List<String> policyItemNames) {
469
 
                Iterator<String> iterator = jsonObject.keys();
470
 
                String key = null;
471
 
                boolean returnValue = false;
472
 
                while(iterator.hasNext()) {
473
 
                        key = iterator.next();
474
 
                        key = key.replaceAll("\\$", "");
475
 
                        policyItemNames.add(key);
476
 
                        try {
477
 
                                if(jsonObject.get(key).equals(formFields.get(key).trim()))
478
 
                                        returnValue = true;
479
 
                                else
480
 
                                        returnValue = false;
481
 
                        } catch(Exception ex) {
482
 
                                LOG.error(ex);
483
 
                                return false;
484
 
                        }
485
 
                }
486
 
                if(!returnValue)
487
 
                        LOG.error("exact match on " + key + " failed");
488
 
                return returnValue;
489
 
        }
490
 
 
491
 
        private boolean partialMatch(JSONArray jsonArray, Map<String, String> formFields, List<String> policyItemNames) {
492
 
                boolean returnValue = false;
493
 
                String key;
494
 
                if(jsonArray.size() != 3)
495
 
                        return false;
496
 
                try {
497
 
                        String condition = (String) jsonArray.get(0);
498
 
                        key = (String) jsonArray.get(1);
499
 
                        key = key.replaceAll("\\$", "");
500
 
                        policyItemNames.add(key);
501
 
                        String value = (String) jsonArray.get(2);
502
 
                        if(condition.contains("eq")) {
503
 
                                if(value.equals(formFields.get(key).trim()))
504
 
                                        returnValue = true;
505
 
                        } else if(condition.contains("starts-with")) {
506
 
                                if(!formFields.containsKey(key))
507
 
                                        return false;
508
 
                                if(formFields.get(key).trim().startsWith(value))
509
 
                                        returnValue = true;
510
 
                        }
511
 
                } catch(Exception ex) {
512
 
                        LOG.error(ex);
513
 
                        return false;
514
 
                }
515
 
                if(!returnValue)
516
 
                        LOG.error("partial match on " + key + " failed");
517
 
                return returnValue;
518
 
        }
519
 
 
520
 
        private static String[] getTarget(MappingHttpRequest httpRequest) {
521
 
                String operationPath = httpRequest.getServicePath().replaceAll(WalrusProperties.walrusServicePath, "");
522
 
                operationPath = operationPath.replaceAll("/{2,}", "/");
523
 
                if(operationPath.startsWith("/"))
524
 
                        operationPath = operationPath.substring(1);
525
 
                return operationPath.split("/");
526
 
        }
527
 
 
528
381
        @Override
529
382
        public void exceptionCaught( final ChannelHandlerContext ctx, final ExceptionEvent exceptionEvent ) throws Exception {
530
383
                LOG.info("[exception " + exceptionEvent + "]");