98
95
import org.jboss.netty.handler.codec.http.HttpVersion;
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;
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());
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." );
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("=", "");
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" );
203
195
protected String checkSignature( final String queryKey, final String subject ) throws AuthenticationException
205
SecretKeySpec signingKey = new SecretKeySpec( queryKey.getBytes(), Hashes.Mac.HmacSHA1.toString() );
197
SecretKeySpec signingKey = new SecretKeySpec( queryKey.getBytes(), Hmac.HmacSHA1.toString() );
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( "=", "" );
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())));
261
policyData = new String(Base64.encode(policy.getBytes()));
262
} catch (Exception ex) {
264
throw new AuthenticationException("error reading policy data.");
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.");
278
List<String> policyItemNames = new ArrayList<String>();
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.");
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.");
298
Set<String> formFieldsKeys = formFields.keySet();
299
for(String formKey : formFieldsKeys) {
300
if(formKey.startsWith(WalrusProperties.IGNORE_PREFIX))
302
boolean fieldOkay = false;
303
for(WalrusProperties.IgnoredFields field : WalrusProperties.IgnoredFields.values()) {
304
if(formKey.equals(field.toString())) {
311
if(policyItemNames.contains(formKey))
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.");
316
} catch(Exception ex) {
319
if(ex instanceof AuthenticationException)
320
throw (AuthenticationException)ex;
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 + ":";
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);
332
httpRequest.addHeader(WalrusProperties.FormField.FormUploadPolicyData.toString(), policyData);
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;
468
private boolean exactMatch(JSONObject jsonObject, Map<String, String> formFields, List<String> policyItemNames) {
469
Iterator<String> iterator = jsonObject.keys();
471
boolean returnValue = false;
472
while(iterator.hasNext()) {
473
key = iterator.next();
474
key = key.replaceAll("\\$", "");
475
policyItemNames.add(key);
477
if(jsonObject.get(key).equals(formFields.get(key).trim()))
481
} catch(Exception ex) {
487
LOG.error("exact match on " + key + " failed");
491
private boolean partialMatch(JSONArray jsonArray, Map<String, String> formFields, List<String> policyItemNames) {
492
boolean returnValue = false;
494
if(jsonArray.size() != 3)
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()))
505
} else if(condition.contains("starts-with")) {
506
if(!formFields.containsKey(key))
508
if(formFields.get(key).trim().startsWith(value))
511
} catch(Exception ex) {
516
LOG.error("partial match on " + key + " failed");
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("/");
529
382
public void exceptionCaught( final ChannelHandlerContext ctx, final ExceptionEvent exceptionEvent ) throws Exception {
530
383
LOG.info("[exception " + exceptionEvent + "]");