diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index c32ecc4bdfb..aec751658b3 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -29,6 +29,7 @@ getSPMetadata=15 listIdps=15 authorizeSamlSso=7 listSamlAuthorization=7 +listAndSwitchSamlAccount=15 ### Account commands createAccount=7 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 index 75353f2c3c4..a6cefb1baf9 100644 --- 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 @@ -267,7 +267,7 @@ public class GetServiceProviderMetaDataCmd extends BaseCmd implements APIAuthent } } if (_samlAuthManager == null) { - s_logger.error("No suitable Pluggable Authentication Manager found for SAML2 Login Cmd"); + s_logger.error("No suitable Pluggable Authentication Manager found for SAML2 getSPMetadata Cmd"); } } } diff --git a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/ListAndSwitchSAMLAccountCmd.java b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/ListAndSwitchSAMLAccountCmd.java new file mode 100644 index 00000000000..db0d6dc7373 --- /dev/null +++ b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/ListAndSwitchSAMLAccountCmd.java @@ -0,0 +1,195 @@ +// 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.domain.Domain; +import com.cloud.domain.dao.DomainDao; +import com.cloud.user.Account; +import com.cloud.user.User; +import com.cloud.user.UserAccount; +import com.cloud.user.UserAccountVO; +import com.cloud.user.dao.UserAccountDao; +import com.cloud.user.dao.UserDao; +import com.cloud.utils.HttpUtils; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.ApiServerService; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +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.DomainResponse; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.LoginCmdResponse; +import org.apache.cloudstack.api.response.SamlUserAccountResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.api.response.UserResponse; +import org.apache.cloudstack.saml.SAML2AuthManager; +import org.apache.cloudstack.saml.SAMLUtils; +import org.apache.log4j.Logger; + +import javax.inject.Inject; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@APICommand(name = "listAndSwitchSamlAccount", description = "Lists and switches to other SAML accounts owned by the SAML user", responseObject = SuccessResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) +public class ListAndSwitchSAMLAccountCmd extends BaseCmd implements APIAuthenticator { + public static final Logger s_logger = Logger.getLogger(ListAndSwitchSAMLAccountCmd.class.getName()); + private static final String s_name = "listandswitchsamlaccountresponse"; + + @Inject + ApiServerService _apiServer; + + @Inject + private UserAccountDao _userAccountDao; + @Inject + private UserDao _userDao; + @Inject + private DomainDao _domainDao; + + SAML2AuthManager _samlAuthManager; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.USER_ID, type = CommandType.UUID, entityType = UserResponse.class, required = false, description = "User uuid") + private Long userId; + + @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, required = false, description = "Domain uuid") + private Long domainId; + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute() { + throw new ServerApiException(ApiErrorCode.METHOD_NOT_ALLOWED, "This is an authentication plugin api, cannot be used directly"); + } + + @Override + public String authenticate(final String command, final Map params, final HttpSession session, final String remoteAddress, final String responseType, final StringBuilder auditTrailSb, final HttpServletRequest req, final HttpServletResponse resp) throws ServerApiException { + if (session == null || session.isNew()) { + throw new ServerApiException(ApiErrorCode.UNAUTHORIZED, _apiServer.getSerializedApiError(ApiErrorCode.UNAUTHORIZED.getHttpCode(), + "Only authenticated saml users can request this API", + params, responseType)); + } + + if (!HttpUtils.validateSessionKey(session, params, req.getCookies(), ApiConstants.SESSIONKEY)) { + throw new ServerApiException(ApiErrorCode.UNAUTHORIZED, _apiServer.getSerializedApiError(ApiErrorCode.UNAUTHORIZED.getHttpCode(), + "Unauthorized session, please re-login", + params, responseType)); + } + + final long currentUserId = (Long) session.getAttribute("userid"); + final UserAccount currentUserAccount = _accountService.getUserAccountById(currentUserId); + if (currentUserAccount == null || currentUserAccount.getSource() != User.Source.SAML2) { + throw new ServerApiException(ApiErrorCode.ACCOUNT_ERROR, _apiServer.getSerializedApiError(ApiErrorCode.ACCOUNT_ERROR.getHttpCode(), + "Only authenticated saml users can request this API", + params, responseType)); + } + + String userUuid = null; + String domainUuid = null; + if (params.containsKey(ApiConstants.USER_ID)) { + userUuid = ((String[])params.get(ApiConstants.USER_ID))[0]; + } + if (params.containsKey(ApiConstants.DOMAIN_ID)) { + domainUuid = ((String[])params.get(ApiConstants.DOMAIN_ID))[0]; + } + + if (userUuid != null && domainUuid != null) { + final User user = _userDao.findByUuid(userUuid); + final Domain domain = _domainDao.findByUuid(domainUuid); + final UserAccount nextUserAccount = _accountService.getUserAccountById(user.getId()); + if (!nextUserAccount.getUsername().equals(currentUserAccount.getUsername()) + || !nextUserAccount.getExternalEntity().equals(currentUserAccount.getExternalEntity()) + || (nextUserAccount.getDomainId() != domain.getId()) + || (nextUserAccount.getSource() != User.Source.SAML2)) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, _apiServer.getSerializedApiError(ApiErrorCode.PARAM_ERROR.getHttpCode(), + "User account is not allowed to switch to the requested account", + params, responseType)); + } + try { + if (_apiServer.verifyUser(nextUserAccount.getId())) { + final LoginCmdResponse loginResponse = (LoginCmdResponse) _apiServer.loginUser(session, nextUserAccount.getUsername(), nextUserAccount.getUsername() + nextUserAccount.getSource().toString(), + nextUserAccount.getDomainId(), null, remoteAddress, params); + SAMLUtils.setupSamlUserCookies(loginResponse, resp); + resp.sendRedirect(SAML2AuthManager.SAMLCloudStackRedirectionUrl.value()); + return ApiResponseSerializer.toSerializedString(loginResponse, responseType); + } + } catch (final Exception ignored) { + } + } else { + List switchableAccounts = _userAccountDao.getAllUsersByNameAndEntity(currentUserAccount.getUsername(), currentUserAccount.getExternalEntity()); + if (switchableAccounts != null && switchableAccounts.size() > 0 && currentUserId != User.UID_SYSTEM) { + List accountResponses = new ArrayList(); + for (UserAccountVO userAccount: switchableAccounts) { + User user = _userDao.getUser(userAccount.getId()); + Domain domain = _domainService.getDomain(userAccount.getDomainId()); + SamlUserAccountResponse accountResponse = new SamlUserAccountResponse(); + accountResponse.setUserId(user.getUuid()); + accountResponse.setUserName(user.getUsername()); + accountResponse.setDomainId(domain.getUuid()); + accountResponse.setDomainName(domain.getName()); + accountResponse.setAccountName(userAccount.getAccountName()); + accountResponse.setIdpId(user.getExternalEntity()); + accountResponses.add(accountResponse); + } + ListResponse response = new ListResponse(); + response.setResponses(accountResponses); + response.setResponseName(getCommandName()); + return ApiResponseSerializer.toSerializedString(response, responseType); + } + } + throw new ServerApiException(ApiErrorCode.ACCOUNT_ERROR, _apiServer.getSerializedApiError(ApiErrorCode.ACCOUNT_ERROR.getHttpCode(), + "Unable to switch to requested SAML account. Please make sure your user/account is enabled. Please contact your administrator.", + params, responseType)); + } + + @Override + public APIAuthenticationType getAPIType() { + return APIAuthenticationType.READONLY_API; + } + + @Override + public void setAuthenticators(List authenticators) { + for (PluggableAPIAuthenticator authManager: authenticators) { + if (authManager != null && authManager instanceof SAML2AuthManager) { + _samlAuthManager = (SAML2AuthManager) authManager; + } + } + if (_samlAuthManager == null) { + s_logger.error("No suitable Pluggable Authentication Manager found for SAML2 listAndSwitchSamlAccount Cmd"); + } + } +} \ No newline at end of file diff --git a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/ListIdpsCmd.java b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/ListIdpsCmd.java index ad387044b5f..026a0ca93c7 100644 --- a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/ListIdpsCmd.java +++ b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/ListIdpsCmd.java @@ -111,4 +111,4 @@ public class ListIdpsCmd extends BaseCmd implements APIAuthenticator { s_logger.error("No suitable Pluggable Authentication Manager found for SAML2 Login Cmd"); } } -} \ No newline at end of file +} diff --git a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmd.java b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmd.java index 8e67408b5f0..f2fcf59c856 100644 --- a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmd.java +++ b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmd.java @@ -17,13 +17,11 @@ package org.apache.cloudstack.api.command; import com.cloud.api.response.ApiResponseSerializer; -import com.cloud.exception.CloudAuthenticationException; import com.cloud.user.Account; import com.cloud.user.DomainManager; import com.cloud.user.UserAccount; import com.cloud.user.UserAccountVO; import com.cloud.user.dao.UserAccountDao; -import com.cloud.utils.HttpUtils; import com.cloud.utils.db.EntityManager; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; @@ -64,7 +62,6 @@ import org.opensaml.xml.validation.ValidationException; import org.xml.sax.SAXException; import javax.inject.Inject; -import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @@ -197,7 +194,6 @@ public class SAML2LoginAPIAuthenticatorCmd extends BaseCmd implements APIAuthent } String username = null; - Long domainId = null; Issuer issuer = processedSAMLResponse.getIssuer(); SAMLProviderMetadata spMetadata = _samlAuthManager.getSPMetadata(); SAMLProviderMetadata idpMetadata = _samlAuthManager.getIdPMetadata(issuer.getValue()); @@ -206,9 +202,6 @@ public class SAML2LoginAPIAuthenticatorCmd extends BaseCmd implements APIAuthent s_logger.debug("Received SAMLResponse in response to id=" + responseToId); SAMLTokenVO token = _samlAuthManager.getToken(responseToId); if (token != null) { - if (token.getDomainId() != null) { - domainId = token.getDomainId(); - } if (!(token.getEntity().equalsIgnoreCase(issuer.getValue()))) { throw new ServerApiException(ApiErrorCode.ACCOUNT_ERROR, _apiServer.getSerializedApiError(ApiErrorCode.ACCOUNT_ERROR.getHttpCode(), "The SAML response contains Issuer Entity ID that is different from the original SAML request", @@ -300,17 +293,9 @@ public class SAML2LoginAPIAuthenticatorCmd extends BaseCmd implements APIAuthent UserAccount userAccount = null; List possibleUserAccounts = _userAccountDao.getAllUsersByNameAndEntity(username, issuer.getValue()); if (possibleUserAccounts != null && possibleUserAccounts.size() > 0) { - if (possibleUserAccounts.size() == 1) { - userAccount = possibleUserAccounts.get(0); - } else if (possibleUserAccounts.size() > 1) { - if (domainId != null) { - userAccount = _userAccountDao.getUserAccount(username, domainId); - } else { - throw new ServerApiException(ApiErrorCode.ACCOUNT_ERROR, _apiServer.getSerializedApiError(ApiErrorCode.ACCOUNT_ERROR.getHttpCode(), - "You have accounts in multiple domains, please re-login by specifying the domain you want to log into.", - params, responseType)); - } - } + // By default, log into the first user account + // Users can switch to other allowed accounts later + userAccount = possibleUserAccounts.get(0); } if (userAccount == null || userAccount.getExternalEntity() == null || !_samlAuthManager.isUserAuthorized(userAccount.getId(), issuer.getValue())) { @@ -324,21 +309,11 @@ public class SAML2LoginAPIAuthenticatorCmd extends BaseCmd implements APIAuthent if (_apiServer.verifyUser(userAccount.getId())) { LoginCmdResponse loginResponse = (LoginCmdResponse) _apiServer.loginUser(session, userAccount.getUsername(), userAccount.getUsername() + userAccount.getSource().toString(), userAccount.getDomainId(), null, remoteAddress, params); - resp.addCookie(new Cookie("userid", URLEncoder.encode(loginResponse.getUserId(), HttpUtils.UTF_8))); - resp.addCookie(new Cookie("domainid", URLEncoder.encode(loginResponse.getDomainId(), HttpUtils.UTF_8))); - resp.addCookie(new Cookie("role", URLEncoder.encode(loginResponse.getType(), HttpUtils.UTF_8))); - resp.addCookie(new Cookie("username", URLEncoder.encode(loginResponse.getUsername(), HttpUtils.UTF_8))); - resp.addCookie(new Cookie("account", URLEncoder.encode(loginResponse.getAccount(), HttpUtils.UTF_8))); - String timezone = loginResponse.getTimeZone(); - if (timezone != null) { - resp.addCookie(new Cookie("timezone", URLEncoder.encode(timezone, HttpUtils.UTF_8))); - } - resp.addCookie(new Cookie("userfullname", URLEncoder.encode(loginResponse.getFirstName() + " " + loginResponse.getLastName(), HttpUtils.UTF_8).replace("+", "%20"))); - resp.addHeader("SET-COOKIE", String.format("%s=%s;HttpOnly", ApiConstants.SESSIONKEY, loginResponse.getSessionKey())); + SAMLUtils.setupSamlUserCookies(loginResponse, resp); resp.sendRedirect(SAML2AuthManager.SAMLCloudStackRedirectionUrl.value()); return ApiResponseSerializer.toSerializedString(loginResponse, responseType); } - } catch (final CloudAuthenticationException ignored) { + } catch (final Exception ignored) { } } } diff --git a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/response/SamlUserAccountResponse.java b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/response/SamlUserAccountResponse.java new file mode 100644 index 00000000000..f0927e3f6d3 --- /dev/null +++ b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/response/SamlUserAccountResponse.java @@ -0,0 +1,99 @@ +// 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; + +public class SamlUserAccountResponse extends AuthenticationCmdResponse { + @SerializedName("userId") + @Param(description = "The User Id") + private String userId; + + @SerializedName("domainId") + @Param(description = "The Domain Id") + private String domainId; + + @SerializedName("userName") + @Param(description = "The User Name") + private String userName; + + @SerializedName("accountName") + @Param(description = "The Account Name") + private String accountName; + + @SerializedName("domainName") + @Param(description = "The Domain Name") + private String domainName; + + @SerializedName("idpId") + @Param(description = "The IDP ID") + private String idpId; + + public SamlUserAccountResponse() { + super(); + setObjectName("samluseraccount"); + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getDomainId() { + return domainId; + } + + public void setDomainId(String domainId) { + this.domainId = domainId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getAccountName() { + return accountName; + } + + public void setAccountName(String accountName) { + this.accountName = accountName; + } + + public String getDomainName() { + return domainName; + } + + public void setDomainName(String domainName) { + this.domainName = domainName; + } + + public String getIdpId() { + return idpId; + } + + public void setIdpId(String idpId) { + this.idpId = idpId; + } +} 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 b1449c1a644..ff644f34948 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 @@ -26,6 +26,7 @@ import com.cloud.utils.component.AdapterBase; import org.apache.cloudstack.api.auth.PluggableAPIAuthenticator; import org.apache.cloudstack.api.command.AuthorizeSAMLSSOCmd; import org.apache.cloudstack.api.command.GetServiceProviderMetaDataCmd; +import org.apache.cloudstack.api.command.ListAndSwitchSAMLAccountCmd; import org.apache.cloudstack.api.command.ListIdpsCmd; import org.apache.cloudstack.api.command.ListSamlAuthorizationCmd; import org.apache.cloudstack.api.command.SAML2LoginAPIAuthenticatorCmd; @@ -506,6 +507,7 @@ public class SAML2AuthManagerImpl extends AdapterBase implements SAML2AuthManage cmdList.add(SAML2LogoutAPIAuthenticatorCmd.class); cmdList.add(GetServiceProviderMetaDataCmd.class); cmdList.add(ListIdpsCmd.class); + cmdList.add(ListAndSwitchSAMLAccountCmd.class); return cmdList; } diff --git a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2UserAuthenticator.java b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2UserAuthenticator.java index 5c8a39088ae..65a7959d997 100644 --- a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2UserAuthenticator.java +++ b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2UserAuthenticator.java @@ -23,18 +23,9 @@ import com.cloud.user.dao.UserDao; import com.cloud.utils.Pair; import org.apache.cxf.common.util.StringUtils; import org.apache.log4j.Logger; -import org.opensaml.DefaultBootstrap; -import org.opensaml.saml2.core.Response; -import org.opensaml.saml2.core.StatusCode; -import org.opensaml.xml.ConfigurationException; -import org.opensaml.xml.io.UnmarshallingException; -import org.xml.sax.SAXException; import javax.ejb.Local; import javax.inject.Inject; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.stream.FactoryConfigurationError; -import java.io.IOException; import java.util.Map; @Local(value = {UserAuthenticator.class}) @@ -63,18 +54,7 @@ public class SAML2UserAuthenticator extends DefaultUserAuthenticator { return new Pair(false, null); } else { User user = _userDao.getUser(userAccount.getId()); - if (user != null && requestParameters != null && requestParameters.containsKey(SAMLPluginConstants.SAML_RESPONSE)) { - final String samlResponse = ((String[])requestParameters.get(SAMLPluginConstants.SAML_RESPONSE))[0]; - Response responseObject = null; - try { - DefaultBootstrap.bootstrap(); - responseObject = SAMLUtils.decodeSAMLResponse(samlResponse); - } catch (ConfigurationException | FactoryConfigurationError | ParserConfigurationException | SAXException | IOException | UnmarshallingException e) { - return new Pair(false, null); - } - if (!responseObject.getStatus().getStatusCode().getValue().equals(StatusCode.SUCCESS_URI)) { - return new Pair(false, null); - } + if (user != null && user.getSource() == User.Source.SAML2 && user.getExternalEntity() != null) { return new Pair(true, null); } } diff --git a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAMLUtils.java b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAMLUtils.java index 77714a1f6a4..ec6b2c11e5e 100644 --- a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAMLUtils.java +++ b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAMLUtils.java @@ -20,6 +20,8 @@ package org.apache.cloudstack.saml; import com.cloud.utils.HttpUtils; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.response.LoginCmdResponse; import org.apache.log4j.Logger; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.x509.X509V1CertificateGenerator; @@ -62,6 +64,8 @@ import org.w3c.dom.Element; import org.xml.sax.SAXException; import javax.security.auth.x500.X500Principal; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletResponse; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -352,4 +356,18 @@ public class SAMLUtils { return certGen.generate(keyPair.getPrivate(), "BC"); } + public static void setupSamlUserCookies(final LoginCmdResponse loginResponse, final HttpServletResponse resp) throws IOException { + resp.addCookie(new Cookie("userid", URLEncoder.encode(loginResponse.getUserId(), HttpUtils.UTF_8))); + resp.addCookie(new Cookie("domainid", URLEncoder.encode(loginResponse.getDomainId(), HttpUtils.UTF_8))); + resp.addCookie(new Cookie("role", URLEncoder.encode(loginResponse.getType(), HttpUtils.UTF_8))); + resp.addCookie(new Cookie("username", URLEncoder.encode(loginResponse.getUsername(), HttpUtils.UTF_8))); + resp.addCookie(new Cookie("account", URLEncoder.encode(loginResponse.getAccount(), HttpUtils.UTF_8))); + String timezone = loginResponse.getTimeZone(); + if (timezone != null) { + resp.addCookie(new Cookie("timezone", URLEncoder.encode(timezone, HttpUtils.UTF_8))); + } + resp.addCookie(new Cookie("userfullname", URLEncoder.encode(loginResponse.getFirstName() + " " + loginResponse.getLastName(), HttpUtils.UTF_8).replace("+", "%20"))); + resp.addHeader("SET-COOKIE", String.format("%s=%s;HttpOnly", ApiConstants.SESSIONKEY, loginResponse.getSessionKey())); + } + } diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index 2bcd5e5a158..60ac9ca4d64 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -9657,7 +9657,7 @@ div.container div.panel div#details-tab-addloadBalancer.detail-group div.loadBal } /*** View switcher (drop-down)*/ -.project-switcher { +.project-switcher, .domain-switcher { float: left; width: 223px; padding: 9px 17px 0 19px; @@ -9668,7 +9668,7 @@ div.container div.panel div#details-tab-addloadBalancer.detail-group div.loadBal border-radius: 4px; } -.project-switcher label { +.project-switcher label, .domain-switcher label { top: 29px; color: #FFFFFF; font-size: 13px; @@ -9677,7 +9677,7 @@ div.container div.panel div#details-tab-addloadBalancer.detail-group div.loadBal margin-top: 5px; } -.project-switcher select { +.project-switcher select, .domain-switcher select { width: 70%; float: left; margin-top: 0px; diff --git a/ui/index.jsp b/ui/index.jsp index e062799618b..01007441cf3 100644 --- a/ui/index.jsp +++ b/ui/index.jsp @@ -75,13 +75,6 @@ -
-
- - -
-
-
" /> @@ -1841,6 +1834,7 @@ + diff --git a/ui/scripts/ui-custom/login.js b/ui/scripts/ui-custom/login.js index e1129583454..58255297a48 100644 --- a/ui/scripts/ui-custom/login.js +++ b/ui/scripts/ui-custom/login.js @@ -122,8 +122,7 @@ } else if (selectedLogin === 'saml') { // SAML args.samlLoginAction({ - data: {'idpid': $login.find('#login-options').find(':selected').val(), - 'domain': $login.find('#saml-domain').val()} + data: {'idpid': $login.find('#login-options').find(':selected').val()} }); } return false; @@ -133,16 +132,13 @@ var toggleLoginView = function (selectedOption) { $login.find('#login-submit').show(); if (selectedOption === '') { - $login.find('#saml-login').hide(); $login.find('#cloudstack-login').hide(); $login.find('#login-submit').hide(); selectedLogin = 'none'; } else if (selectedOption === 'cloudstack-login') { - $login.find('#saml-login').hide(); $login.find('#cloudstack-login').show(); selectedLogin = 'cloudstack'; } else { - $login.find('#saml-login').show(); $login.find('#cloudstack-login').hide(); selectedLogin = 'saml'; } @@ -160,14 +156,12 @@ $login.find('#login-dropdown').hide(); $login.find('#login-submit').show(); $login.find('#cloudstack-login').show(); - $login.find('#saml-login').hide(); // If any IdP servers were set, SAML is enabled if (g_idpList && g_idpList.length > 0) { $login.find('#login-dropdown').show(); $login.find('#login-submit').hide(); $login.find('#cloudstack-login').hide(); - $login.find('#saml-login').hide(); $login.find('#login-options') .append($('