You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by bh...@apache.org on 2014/08/25 17:36:30 UTC
[34/52] git commit: updated refs/heads/saml2 to 1d809ff
saml2: Add GetServiceProviderMetaDataCmd that returns SP metadata XML
This adds GetServiceProviderMetaDataCmd which returns SP metadata XML, since
this information should be public for IdPs to discover, we implement this as a
login/cmd api so this does not require any kind of authentication to GET this
Signed-off-by: Rohit Yadav <ro...@shapeblue.com>
Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/99ae373b
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/99ae373b
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/99ae373b
Branch: refs/heads/saml2
Commit: 99ae373b9eb7dbe74e4802ab6e3bb8b2b2f60c1a
Parents: b84b2c1
Author: Rohit Yadav <ro...@shapeblue.com>
Authored: Mon Aug 25 00:13:32 2014 +0200
Committer: Rohit Yadav <ro...@shapeblue.com>
Committed: Mon Aug 25 17:33:28 2014 +0200
----------------------------------------------------------------------
.../command/GetServiceProviderMetaDataCmd.java | 202 +++++++++++++++++++
.../api/response/SAMLMetaDataResponse.java | 40 ++++
.../cloudstack/saml/SAML2AuthManagerImpl.java | 2 +
3 files changed, 244 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99ae373b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/GetServiceProviderMetaDataCmd.java
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/GetServiceProviderMetaDataCmd.java b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/GetServiceProviderMetaDataCmd.java
new file mode 100644
index 0000000..16ee088
--- /dev/null
+++ b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/GetServiceProviderMetaDataCmd.java
@@ -0,0 +1,202 @@
+// 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.cloudstack.api.command;
+
+import com.cloud.api.response.ApiResponseSerializer;
+import com.cloud.user.Account;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.ApiServerService;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.auth.APIAuthenticationType;
+import org.apache.cloudstack.api.auth.APIAuthenticator;
+import org.apache.cloudstack.api.auth.PluggableAPIAuthenticator;
+import org.apache.cloudstack.api.response.SAMLMetaDataResponse;
+import org.apache.cloudstack.saml.SAML2AuthManager;
+import org.apache.log4j.Logger;
+import org.opensaml.Configuration;
+import org.opensaml.DefaultBootstrap;
+import org.opensaml.common.xml.SAMLConstants;
+import org.opensaml.saml2.core.NameIDType;
+import org.opensaml.saml2.metadata.AssertionConsumerService;
+import org.opensaml.saml2.metadata.EntityDescriptor;
+import org.opensaml.saml2.metadata.KeyDescriptor;
+import org.opensaml.saml2.metadata.NameIDFormat;
+import org.opensaml.saml2.metadata.SPSSODescriptor;
+import org.opensaml.saml2.metadata.SingleLogoutService;
+import org.opensaml.saml2.metadata.impl.AssertionConsumerServiceBuilder;
+import org.opensaml.saml2.metadata.impl.EntityDescriptorBuilder;
+import org.opensaml.saml2.metadata.impl.KeyDescriptorBuilder;
+import org.opensaml.saml2.metadata.impl.NameIDFormatBuilder;
+import org.opensaml.saml2.metadata.impl.SPSSODescriptorBuilder;
+import org.opensaml.saml2.metadata.impl.SingleLogoutServiceBuilder;
+import org.opensaml.xml.ConfigurationException;
+import org.opensaml.xml.io.Marshaller;
+import org.opensaml.xml.io.MarshallingException;
+import org.opensaml.xml.security.SecurityException;
+import org.opensaml.xml.security.credential.UsageType;
+import org.opensaml.xml.security.keyinfo.KeyInfoGenerator;
+import org.opensaml.xml.security.x509.BasicX509Credential;
+import org.opensaml.xml.security.x509.X509KeyInfoGeneratorFactory;
+import org.w3c.dom.Document;
+
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.FactoryConfigurationError;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.List;
+import java.util.Map;
+
+@APICommand(name = "getSPMetadata", description = "Returns SAML2 CloudStack Service Provider MetaData", responseObject = SAMLMetaDataResponse.class, entityType = {})
+public class GetServiceProviderMetaDataCmd extends BaseCmd implements APIAuthenticator {
+ public static final Logger s_logger = Logger.getLogger(GetServiceProviderMetaDataCmd.class.getName());
+ private static final String s_name = "spmetadataresponse";
+
+ @Inject
+ ApiServerService _apiServer;
+
+ SAML2AuthManager _samlAuthManager;
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public String getCommandName() {
+ return s_name;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return Account.ACCOUNT_TYPE_NORMAL;
+ }
+
+ @Override
+ public void execute() throws ServerApiException {
+ throw new ServerApiException(ApiErrorCode.METHOD_NOT_ALLOWED, "This is an authentication plugin api, cannot be used directly");
+ }
+
+ @Override
+ public String authenticate(String command, Map<String, Object[]> params, HttpSession session, String remoteAddress, String responseType, StringBuilder auditTrailSb, HttpServletResponse resp) throws ServerApiException {
+ SAMLMetaDataResponse response = new SAMLMetaDataResponse();
+ response.setResponseName(getCommandName());
+
+ try {
+ DefaultBootstrap.bootstrap();
+ } catch (ConfigurationException | FactoryConfigurationError e) {
+ s_logger.error("OpenSAML Bootstrapping error: " + e.getMessage());
+ throw new ServerApiException(ApiErrorCode.ACCOUNT_ERROR, _apiServer.getSerializedApiError(ApiErrorCode.ACCOUNT_ERROR.getHttpCode(),
+ "OpenSAML Bootstrapping error while creating SP MetaData",
+ params, responseType));
+ }
+
+ EntityDescriptor spEntityDescriptor = new EntityDescriptorBuilder().buildObject();
+ spEntityDescriptor.setEntityID(_samlAuthManager.getServiceProviderId());
+
+ SPSSODescriptor spSSODescriptor = new SPSSODescriptorBuilder().buildObject();
+ spSSODescriptor.setWantAssertionsSigned(true);
+ spSSODescriptor.setAuthnRequestsSigned(false);
+
+ X509KeyInfoGeneratorFactory keyInfoGeneratorFactory = new X509KeyInfoGeneratorFactory();
+ keyInfoGeneratorFactory.setEmitEntityCertificate(true);
+ KeyInfoGenerator keyInfoGenerator = keyInfoGeneratorFactory.newInstance();
+
+ KeyDescriptor encKeyDescriptor = new KeyDescriptorBuilder().buildObject();
+ encKeyDescriptor.setUse(UsageType.ENCRYPTION);
+
+ KeyDescriptor signKeyDescriptor = new KeyDescriptorBuilder().buildObject();
+ signKeyDescriptor.setUse(UsageType.SIGNING);
+
+ BasicX509Credential credential = new BasicX509Credential();
+ credential.setEntityCertificate(_samlAuthManager.getIdpSigningKey());
+ try {
+ encKeyDescriptor.setKeyInfo(keyInfoGenerator.generate(credential));
+ signKeyDescriptor.setKeyInfo(keyInfoGenerator.generate(credential));
+ //TODO: generate own pub/priv keys
+ //spSSODescriptor.getKeyDescriptors().add(encKeyDescriptor);
+ //spSSODescriptor.getKeyDescriptors().add(signKeyDescriptor);
+ } catch (SecurityException ignored) {
+ }
+
+ NameIDFormat nameIDFormat = new NameIDFormatBuilder().buildObject();
+ nameIDFormat.setFormat(NameIDType.PERSISTENT);
+ spSSODescriptor.getNameIDFormats().add(nameIDFormat);
+
+ AssertionConsumerService assertionConsumerService = new AssertionConsumerServiceBuilder().buildObject();
+ assertionConsumerService.setIndex(0);
+ assertionConsumerService.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI);
+ assertionConsumerService.setLocation(_samlAuthManager.getSpSingleSignOnUrl());
+
+ SingleLogoutService ssoService = new SingleLogoutServiceBuilder().buildObject();
+ ssoService.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI);
+ ssoService.setLocation(_samlAuthManager.getSpSingleLogOutUrl());
+
+ spSSODescriptor.getSingleLogoutServices().add(ssoService);
+ spSSODescriptor.getAssertionConsumerServices().add(assertionConsumerService);
+ spSSODescriptor.addSupportedProtocol(SAMLConstants.SAML20P_NS);
+ spEntityDescriptor.getRoleDescriptors().add(spSSODescriptor);
+
+ try {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ Document document = builder.newDocument();
+ Marshaller out = Configuration.getMarshallerFactory().getMarshaller(spEntityDescriptor);
+ out.marshall(spEntityDescriptor, document);
+
+ Transformer transformer = TransformerFactory.newInstance().newTransformer();
+ StringWriter stringWriter = new StringWriter();
+ StreamResult streamResult = new StreamResult(stringWriter);
+ DOMSource source = new DOMSource(document);
+ transformer.transform(source, streamResult);
+ stringWriter.close();
+ response.setMetadata(stringWriter.toString());
+ } catch (ParserConfigurationException | IOException | MarshallingException | TransformerException e) {
+ response.setMetadata("Error creating Service Provider MetaData XML: " + e.getMessage());
+ }
+
+ return ApiResponseSerializer.toSerializedString(response, responseType);
+ }
+
+ @Override
+ public APIAuthenticationType getAPIType() {
+ return APIAuthenticationType.LOGIN_API;
+ }
+
+ @Override
+ public void setAuthenticators(List<PluggableAPIAuthenticator> authenticators) {
+ for (PluggableAPIAuthenticator authManager: authenticators) {
+ if (authManager instanceof SAML2AuthManager) {
+ _samlAuthManager = (SAML2AuthManager) authManager;
+ }
+ }
+ if (_samlAuthManager == null) {
+ s_logger.error("No suitable Pluggable Authentication Manager found for SAML2 Login Cmd");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99ae373b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/response/SAMLMetaDataResponse.java
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/response/SAMLMetaDataResponse.java b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/response/SAMLMetaDataResponse.java
new file mode 100644
index 0000000..e091ea4
--- /dev/null
+++ b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/response/SAMLMetaDataResponse.java
@@ -0,0 +1,40 @@
+// 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.cloudstack.api.response;
+
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+import org.apache.cloudstack.api.BaseResponse;
+
+public class SAMLMetaDataResponse extends BaseResponse {
+
+ @SerializedName("metadata")
+ @Param(description = "The Metadata XML")
+ private String metadata;
+
+ public SAMLMetaDataResponse() {
+ super();
+ }
+
+ public String getMetadata() {
+ return metadata;
+ }
+
+ public void setMetadata(String metadata) {
+ this.metadata = metadata;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/99ae373b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java
index 7ef126a..22d99cb 100644
--- a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java
+++ b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java
@@ -19,6 +19,7 @@ package org.apache.cloudstack.saml;
import com.cloud.configuration.Config;
import com.cloud.utils.component.AdapterBase;
import org.apache.cloudstack.api.auth.PluggableAPIAuthenticator;
+import org.apache.cloudstack.api.command.GetServiceProviderMetaDataCmd;
import org.apache.cloudstack.api.command.SAML2LoginAPIAuthenticatorCmd;
import org.apache.cloudstack.api.command.SAML2LogoutAPIAuthenticatorCmd;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
@@ -147,6 +148,7 @@ public class SAML2AuthManagerImpl extends AdapterBase implements SAML2AuthManage
List<Class<?>> cmdList = new ArrayList<Class<?>>();
cmdList.add(SAML2LoginAPIAuthenticatorCmd.class);
cmdList.add(SAML2LogoutAPIAuthenticatorCmd.class);
+ cmdList.add(GetServiceProviderMetaDataCmd.class);
return cmdList;
}