You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by lq...@apache.org on 2016/02/16 17:57:43 UTC
svn commit: r1730713 - in
/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/group/cloudfoundry:
./ CloudFoundryDashboardManagementGroupProvider.java
CloudFoundryDashboardManagementGroupProviderImpl.java
Author: lquack
Date: Tue Feb 16 16:57:43 2016
New Revision: 1730713
URL: http://svn.apache.org/viewvc?rev=1730713&view=rev
Log:
QPID-7069: [Java Broker] Add CloudFoundry specific GroupProvider
Added:
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/group/cloudfoundry/
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/group/cloudfoundry/CloudFoundryDashboardManagementGroupProvider.java
qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/group/cloudfoundry/CloudFoundryDashboardManagementGroupProviderImpl.java
Added: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/group/cloudfoundry/CloudFoundryDashboardManagementGroupProvider.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/group/cloudfoundry/CloudFoundryDashboardManagementGroupProvider.java?rev=1730713&view=auto
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/group/cloudfoundry/CloudFoundryDashboardManagementGroupProvider.java (added)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/group/cloudfoundry/CloudFoundryDashboardManagementGroupProvider.java Tue Feb 16 16:57:43 2016
@@ -0,0 +1,62 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.security.group.cloudfoundry;
+
+import java.net.URI;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.server.model.DerivedAttribute;
+import org.apache.qpid.server.model.GroupProvider;
+import org.apache.qpid.server.model.ManagedAttribute;
+import org.apache.qpid.server.model.ManagedContextDefault;
+import org.apache.qpid.server.model.ManagedObject;
+import org.apache.qpid.server.model.TrustStore;
+
+@ManagedObject( category = false, type = "CloudFoundryDashboardManagement" )
+public interface CloudFoundryDashboardManagementGroupProvider<X extends CloudFoundryDashboardManagementGroupProvider<X>> extends GroupProvider<X>
+{
+ String QPID_GROUPPROVIDER_CLOUDFOUNDRY_CONNECT_TIMEOUT = "qpid.groupprovider.cloudfoundry.connectTimeout";
+ @ManagedContextDefault(name = QPID_GROUPPROVIDER_CLOUDFOUNDRY_CONNECT_TIMEOUT)
+ int DEFAULT_QPID_GROUPPROVIDER_CLOUDFOUNDRY_CONNECT_TIMEOUT = 60000;
+
+ String QPID_GROUPPROVIDER_CLOUDFOUNDRY_READ_TIMEOUT = "qpid.groupprovider.cloudfoundry.readTimeout";
+ @ManagedContextDefault(name = QPID_GROUPPROVIDER_CLOUDFOUNDRY_READ_TIMEOUT)
+ int DEFAULT_QPID_GROUPPROVIDER_CLOUDFOUNDRY_READ_TIMEOUT = 60000;
+
+ @ManagedAttribute( mandatory = true )
+ URI getCloudFoundryEndpointURI();
+
+ @ManagedAttribute()
+ TrustStore getTrustStore();
+
+ @ManagedAttribute( mandatory = true )
+ Map<String, String> getServiceToManagementGroupMapping();
+
+ @DerivedAttribute
+ List<String> getTlsProtocolWhiteList();
+ @DerivedAttribute
+ List<String> getTlsProtocolBlackList();
+ @DerivedAttribute
+ List<String> getTlsCipherSuiteWhiteList();
+ @DerivedAttribute
+ List<String> getTlsCipherSuiteBlackList();
+}
Added: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/group/cloudfoundry/CloudFoundryDashboardManagementGroupProviderImpl.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/group/cloudfoundry/CloudFoundryDashboardManagementGroupProviderImpl.java?rev=1730713&view=auto
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/group/cloudfoundry/CloudFoundryDashboardManagementGroupProviderImpl.java (added)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/security/group/cloudfoundry/CloudFoundryDashboardManagementGroupProviderImpl.java Tue Feb 16 16:57:43 2016
@@ -0,0 +1,272 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.security.group.cloudfoundry;
+
+import static org.apache.qpid.configuration.CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_BLACK_LIST;
+import static org.apache.qpid.configuration.CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_WHITE_LIST;
+import static org.apache.qpid.configuration.CommonProperties.QPID_SECURITY_TLS_PROTOCOL_BLACK_LIST;
+import static org.apache.qpid.configuration.CommonProperties.QPID_SECURITY_TLS_PROTOCOL_WHITE_LIST;
+import static org.apache.qpid.server.util.ParameterizedTypes.LIST_OF_STRINGS;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+import java.security.Principal;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.qpid.server.configuration.IllegalConfigurationException;
+import org.apache.qpid.server.model.AbstractConfiguredObject;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.ManagedAttributeField;
+import org.apache.qpid.server.model.ManagedObjectFactoryConstructor;
+import org.apache.qpid.server.model.TrustStore;
+import org.apache.qpid.server.security.auth.manager.oauth2.OAuth2UserPrincipal;
+import org.apache.qpid.server.security.group.GroupPrincipal;
+import org.apache.qpid.server.util.ConnectionBuilder;
+import org.apache.qpid.server.util.ConnectionScopedRuntimeException;
+import org.apache.qpid.server.util.ServerScopedRuntimeException;
+
+/*
+ * This GroupProvider checks a CloudFoundry service dashboard to see whether a certain user (represented by an
+ * accessToken) has permission to manage a set of service instances and adds corresponding GroupPrincipals.
+ * See the CloudFoundry docs for more information:
+ * http://docs.cloudfoundry.org/services/dashboard-sso.html#checking-user-permissions
+ */
+public class CloudFoundryDashboardManagementGroupProviderImpl extends AbstractConfiguredObject<CloudFoundryDashboardManagementGroupProviderImpl>
+ implements CloudFoundryDashboardManagementGroupProvider<CloudFoundryDashboardManagementGroupProviderImpl>
+{
+ private static final Logger LOGGER = LoggerFactory.getLogger(CloudFoundryDashboardManagementGroupProviderImpl.class);
+ private static final String UTF8 = StandardCharsets.UTF_8.name();
+
+ private final ObjectMapper _objectMapper = new ObjectMapper();
+
+ @ManagedAttributeField
+ private URI _cloudFoundryEndpointURI;
+
+ @ManagedAttributeField
+ private TrustStore _trustStore;
+
+ @ManagedAttributeField
+ private Map<String, String> _serviceToManagementGroupMapping;
+
+ private List<String> _tlsProtocolWhiteList;
+ private List<String> _tlsProtocolBlackList;
+ private List<String> _tlsCipherSuiteWhiteList;
+ private List<String> _tlsCipherSuiteBlackList;
+ private int _connectTimeout;
+ private int _readTimeout;
+
+ @ManagedObjectFactoryConstructor
+ public CloudFoundryDashboardManagementGroupProviderImpl(Map<String, Object> attributes, Broker broker)
+ {
+ super(parentsMap(broker), attributes);
+ }
+
+ @Override
+ public void onOpen()
+ {
+ super.onOpen();
+ _tlsProtocolWhiteList = getContextValue(List.class, LIST_OF_STRINGS, QPID_SECURITY_TLS_PROTOCOL_WHITE_LIST);
+ _tlsProtocolBlackList = getContextValue(List.class, LIST_OF_STRINGS, QPID_SECURITY_TLS_PROTOCOL_BLACK_LIST);
+ _tlsCipherSuiteWhiteList = getContextValue(List.class, LIST_OF_STRINGS, QPID_SECURITY_TLS_CIPHER_SUITE_WHITE_LIST);
+ _tlsCipherSuiteBlackList = getContextValue(List.class, LIST_OF_STRINGS, QPID_SECURITY_TLS_CIPHER_SUITE_BLACK_LIST);
+ _connectTimeout = getContextValue(Integer.class, QPID_GROUPPROVIDER_CLOUDFOUNDRY_CONNECT_TIMEOUT);
+ _readTimeout = getContextValue(Integer.class, QPID_GROUPPROVIDER_CLOUDFOUNDRY_READ_TIMEOUT);
+ }
+
+ @Override
+ protected void validateChange(final ConfiguredObject<?> proxyForValidation, final Set<String> changedAttributes)
+ {
+ super.validateChange(proxyForValidation, changedAttributes);
+ final CloudFoundryDashboardManagementGroupProvider<?> validationProxy = (CloudFoundryDashboardManagementGroupProvider<?>) proxyForValidation;
+ validateSecureEndpoint(validationProxy);
+ }
+
+ @Override
+ public void onValidate()
+ {
+ super.onValidate();
+ validateSecureEndpoint(this);
+ }
+
+ private void validateSecureEndpoint(final CloudFoundryDashboardManagementGroupProvider<?> provider)
+ {
+ if (!"https".equals(provider.getCloudFoundryEndpointURI().getScheme()))
+ {
+ throw new IllegalConfigurationException(String.format("CloudFoundryDashboardManagementEndpoint is not secure: '%s'",
+ provider.getCloudFoundryEndpointURI()));
+ }
+ }
+
+ @Override
+ public Set<Principal> getGroupPrincipalsForUser(Principal userPrincipal)
+ {
+ if (!(userPrincipal instanceof OAuth2UserPrincipal))
+ {
+ return Collections.emptySet();
+ }
+ if (_serviceToManagementGroupMapping == null)
+ {
+ throw new IllegalConfigurationException("CloudFoundryDashboardManagementGroupProvider serviceToManagementGroupMapping may not be null");
+ }
+
+ OAuth2UserPrincipal oauth2UserPrincipal = (OAuth2UserPrincipal) userPrincipal;
+ String accessToken = oauth2UserPrincipal.getAccessToken();
+ Set<Principal> groupPrincipals = new HashSet<>();
+
+ for (Map.Entry<String, String> entry : _serviceToManagementGroupMapping.entrySet())
+ {
+ String serviceInstanceId = entry.getKey();
+ String managementGroupName = entry.getValue();
+ if (mayManageServiceInstance(serviceInstanceId, accessToken))
+ {
+ LOGGER.debug("Adding group '{}' to the set of Principals", managementGroupName);
+ groupPrincipals.add(new GroupPrincipal(managementGroupName));
+ }
+ else
+ {
+ LOGGER.debug("CloudFoundryDashboardManagementEndpoint denied management permission for service instance '{}'", serviceInstanceId);
+ }
+ }
+ return groupPrincipals;
+ }
+
+ private boolean mayManageServiceInstance(final String serviceInstanceId, final String accessToken)
+ {
+ HttpURLConnection connection;
+ String cloudFoundryEndpoint = String.format("%s/v2/service_instances/%s/permissions",
+ getCloudFoundryEndpointURI().toString(), serviceInstanceId);
+ try
+ {
+ ConnectionBuilder connectionBuilder = new ConnectionBuilder(new URL(cloudFoundryEndpoint));
+ connectionBuilder.setConnectTimeout(_connectTimeout).setReadTimeout(_readTimeout);
+ if (_trustStore != null)
+ {
+ try
+ {
+ connectionBuilder.setTrustMangers(_trustStore.getTrustManagers());
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new ServerScopedRuntimeException("Cannot initialise TLS", e);
+ }
+ }
+ connectionBuilder.setTlsProtocolWhiteList(_tlsProtocolWhiteList)
+ .setTlsProtocolBlackList(_tlsProtocolBlackList)
+ .setTlsCipherSuiteWhiteList(_tlsCipherSuiteWhiteList)
+ .setTlsCipherSuiteBlackList(_tlsCipherSuiteBlackList);
+
+ LOGGER.debug("About to call CloudFoundryDashboardManagementEndpoint '{}'", cloudFoundryEndpoint);
+ connection = connectionBuilder.build();
+
+ connection.setRequestProperty("Accept-Charset", UTF8);
+ connection.setRequestProperty("Accept", "application/json");
+ connection.setRequestProperty("Authorization", "Bearer " + accessToken);
+
+ connection.connect();
+ }
+ catch (IOException e)
+ {
+ throw new ConnectionScopedRuntimeException(String.format("Could not connect to CloudFoundryDashboardManagementEndpoint '%s'.",
+ cloudFoundryEndpoint), e);
+ }
+
+ try (InputStream input = connection.getInputStream())
+ {
+ final int responseCode = connection.getResponseCode();
+ LOGGER.debug("Call to CloudFoundryDashboardManagementEndpoint '{}' complete, response code : {}", cloudFoundryEndpoint, responseCode);
+
+ Map<String, Object> responseMap = _objectMapper.readValue(input, Map.class);
+ Object mayManageObject = responseMap.get("manage");
+ if (mayManageObject == null || !(mayManageObject instanceof Boolean))
+ {
+ throw new ConnectionScopedRuntimeException("CloudFoundryDashboardManagementEndpoint response did not contain \"manage\" entry.");
+ }
+ return (boolean) mayManageObject;
+ }
+ catch (JsonProcessingException e)
+ {
+ throw new ConnectionScopedRuntimeException(String.format("CloudFoundryDashboardManagementEndpoint '%s' did not return json",
+ cloudFoundryEndpoint), e);
+ }
+ catch (IOException e)
+ {
+ throw new ConnectionScopedRuntimeException(String.format("Connection to CloudFoundryDashboardManagementEndpoint '%s' failed",
+ cloudFoundryEndpoint), e);
+ }
+ }
+
+ @Override
+ public URI getCloudFoundryEndpointURI()
+ {
+ return _cloudFoundryEndpointURI;
+ }
+
+ @Override
+ public TrustStore getTrustStore()
+ {
+ return _trustStore;
+ }
+
+ @Override
+ public Map<String, String> getServiceToManagementGroupMapping()
+ {
+ return _serviceToManagementGroupMapping;
+ }
+
+ @Override
+ public List<String> getTlsProtocolWhiteList()
+ {
+ return _tlsProtocolWhiteList;
+ }
+
+ @Override
+ public List<String> getTlsProtocolBlackList()
+ {
+ return _tlsProtocolBlackList;
+ }
+
+ @Override
+ public List<String> getTlsCipherSuiteWhiteList()
+ {
+ return _tlsCipherSuiteWhiteList;
+ }
+
+ @Override
+ public List<String> getTlsCipherSuiteBlackList()
+ {
+ return _tlsCipherSuiteBlackList;
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org