/************************************************************************* * (c) Copyright 2016 Hewlett Packard Enterprise Development Company LP * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. ************************************************************************/ package com.eucalyptus.simplequeue.ws; import com.eucalyptus.auth.euare.DelegatingUserPrincipal; import com.eucalyptus.auth.login.AuthenticationException; import com.eucalyptus.auth.principal.PolicyVersion; import com.eucalyptus.auth.principal.PolicyVersions; import com.eucalyptus.auth.principal.Principals; import com.eucalyptus.auth.principal.TemporaryAccessKey; import com.eucalyptus.auth.principal.UserPrincipal; import com.eucalyptus.component.annotation.ComponentPart; import com.eucalyptus.context.Context; import com.eucalyptus.context.Contexts; import com.eucalyptus.crypto.util.SecurityHeader; import com.eucalyptus.crypto.util.SecurityParameter; import com.eucalyptus.http.MappingHttpRequest; import com.eucalyptus.simplequeue.SimpleQueue; import com.eucalyptus.simplequeue.config.SimpleQueueConfiguration; import com.eucalyptus.ws.handlers.MessageStackHandler; import com.eucalyptus.ws.protocol.OperationParameter; import com.eucalyptus.ws.server.QueryPipeline; import com.eucalyptus.ws.stages.UnrollableStage; import com.eucalyptus.ws.util.HmacUtils; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import org.apache.log4j.Logger; import org.jboss.netty.channel.ChannelHandler; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.handler.codec.http.HttpHeaders; import javax.annotation.Nonnull; import javax.security.auth.Subject; import java.util.EnumSet; import java.util.List; import java.util.Map; import java.util.regex.Pattern; /** * @author Chris Grzegorczyk <grze@eucalyptus.com> */ @ComponentPart(SimpleQueue.class) public class SimpleQueueQueryPipeline extends QueryPipeline { private final SimpleQueueAuthenticationStage auth = new SimpleQueueAuthenticationStage( super.getAuthenticationStage() ); private static final Logger LOG = Logger.getLogger(SimpleQueueQueryPipeline.class); private static final Pattern pathPattern = Pattern.compile("/[0-9]{12}/[A-Za-z0-9_-]+"); public SimpleQueueQueryPipeline(final String name) { super( name, SimpleQueueConfiguration.SERVICE_PATH, EnumSet.allOf( TemporaryAccessKey.TemporaryKeyType.class ) ); } public SimpleQueueQueryPipeline() { this("simplequeue-query-pipeline"); } @Override public ChannelPipeline addHandlers( final ChannelPipeline pipeline ) { super.addHandlers( pipeline ); pipeline.addLast( "simplequeue-query-binding", new SimpleQueueQueueUrlQueryBinding(pipeline) ); return pipeline; } @Override protected boolean validPathForService( final String path ) { return super.validPathForService( path ) || pathPattern.matcher( path ).matches( ); } @Override protected UnrollableStage getAuthenticationStage() { return auth; } private static class SimpleQueueAuthenticationStage implements UnrollableStage { private final UnrollableStage standardAuthenticationStage; private SimpleQueueAuthenticationStage(final UnrollableStage standardAuthenticationStage) { this.standardAuthenticationStage = standardAuthenticationStage; } @Override public void unrollStage( final ChannelPipeline pipeline ) { pipeline.addLast( "simplequeue-authentication-method-selector", new SimpleQueueAuthenticationHandler( standardAuthenticationStage ) ); } @Override public String getName() { return "simplequeue-user-authentication"; } @Override public int compareTo( UnrollableStage o ) { return this.getName( ).compareTo( o.getName( ) ); } } public static class SimpleQueueAuthenticationHandler extends MessageStackHandler { private final UnrollableStage standardAuthenticationStage; public SimpleQueueAuthenticationHandler(final UnrollableStage standardAuthenticationStage) { this.standardAuthenticationStage = standardAuthenticationStage; } @Override public void incomingMessage( final MessageEvent event ) throws Exception { if ( event.getMessage( ) instanceof MappingHttpRequest) { boolean isHmac = true; final MappingHttpRequest httpRequest = ( MappingHttpRequest ) event.getMessage( ); isHmac = !HmacUtils.signatureVariantOption(httpRequest).isEmpty(); final ChannelPipeline stagePipeline = Channels.pipeline(); if ( isHmac ) { standardAuthenticationStage.unrollStage( stagePipeline ); } else { stagePipeline.addLast( "simplequeue-anonymous", new AnonymousRequestHandler( ) ); } final ChannelPipeline pipeline = event.getChannel().getPipeline(); String addAfter = "simplequeue-authentication-method-selector"; for ( final Map.Entry<String,ChannelHandler> handlerEntry : stagePipeline.toMap().entrySet() ) { pipeline.addAfter( addAfter, handlerEntry.getKey(), handlerEntry.getValue() ); addAfter = handlerEntry.getKey(); } } } } public static class AnonymousRequestHandler extends MessageStackHandler { @Override public void incomingMessage( final MessageEvent event ) throws Exception { if ( event.getMessage( ) instanceof MappingHttpRequest ) { final MappingHttpRequest httpRequest = ( MappingHttpRequest ) event.getMessage( ); final Context context = Contexts.lookup( httpRequest.getCorrelationId( ) ); final Subject subject = new Subject( ); final UserPrincipal principal = new DelegatingUserPrincipal( Principals.nobodyUser( ) ) { @Nonnull @Override public List<PolicyVersion> getPrincipalPolicies( ) { return ImmutableList.of( PolicyVersions.getAdministratorPolicy( ) ); } }; subject.getPrincipals( ).add( principal ); context.setUser( principal ); context.setSubject( subject ); } } } }