mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Merge remote-tracking branch 'origin/4.17'
This commit is contained in:
commit
e57a0f9980
@ -53,5 +53,11 @@
|
||||
<version>${cs.xercesImpl.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>${cs.assertj.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@ -150,7 +150,8 @@ public class SAMLUtils {
|
||||
if (spMetadata.getKeyPair() != null) {
|
||||
privateKey = spMetadata.getKeyPair().getPrivate();
|
||||
}
|
||||
redirectUrl = idpMetadata.getSsoUrl() + "?" + SAMLUtils.generateSAMLRequestSignature("SAMLRequest=" + SAMLUtils.encodeSAMLRequest(authnRequest), privateKey, signatureAlgorithm);
|
||||
String appendOperator = idpMetadata.getSsoUrl().contains("?") ? "&" : "?";
|
||||
redirectUrl = idpMetadata.getSsoUrl() + appendOperator + SAMLUtils.generateSAMLRequestSignature("SAMLRequest=" + SAMLUtils.encodeSAMLRequest(authnRequest), privateKey, signatureAlgorithm);
|
||||
} catch (ConfigurationException | FactoryConfigurationError | MarshallingException | IOException | NoSuchAlgorithmException | InvalidKeyException | java.security.SignatureException e) {
|
||||
s_logger.error("SAML AuthnRequest message building error: " + e.getMessage());
|
||||
}
|
||||
|
||||
@ -19,18 +19,22 @@
|
||||
|
||||
package org.apache.cloudstack;
|
||||
|
||||
import java.security.KeyPair;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.apache.cloudstack.saml.SAML2AuthManager;
|
||||
import org.apache.cloudstack.saml.SAMLProviderMetadata;
|
||||
import org.apache.cloudstack.saml.SAMLUtils;
|
||||
import org.apache.cloudstack.utils.security.CertUtils;
|
||||
import org.junit.Test;
|
||||
import org.opensaml.saml2.core.AuthnRequest;
|
||||
import org.opensaml.saml2.core.LogoutRequest;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import java.net.URI;
|
||||
import java.security.KeyPair;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class SAMLUtilsTest extends TestCase {
|
||||
|
||||
@ -60,6 +64,63 @@ public class SAMLUtilsTest extends TestCase {
|
||||
assertEquals(req.getIssuer().getValue(), spId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildAuthnRequestUrlWithoutQueryParam() throws Exception {
|
||||
String urlScheme = "http";
|
||||
|
||||
String spDomain = "sp.domain.example";
|
||||
String spUrl = urlScheme + "://" + spDomain;
|
||||
String spId = "serviceProviderId";
|
||||
|
||||
String idpDomain = "idp.domain.example";
|
||||
String idpUrl = urlScheme + "://" + idpDomain;
|
||||
String idpId = "identityProviderId";
|
||||
|
||||
String authnId = SAMLUtils.generateSecureRandomId();
|
||||
|
||||
SAMLProviderMetadata spMetadata = new SAMLProviderMetadata();
|
||||
spMetadata.setEntityId(spId);
|
||||
spMetadata.setSsoUrl(spUrl);
|
||||
|
||||
SAMLProviderMetadata idpMetadata = new SAMLProviderMetadata();
|
||||
idpMetadata.setSsoUrl(idpUrl);
|
||||
idpMetadata.setEntityId(idpId);
|
||||
|
||||
URI redirectUrl = new URI(SAMLUtils.buildAuthnRequestUrl(authnId, spMetadata, idpMetadata, SAML2AuthManager.SAMLSignatureAlgorithm.value()));
|
||||
assertThat(redirectUrl).hasScheme(urlScheme).hasHost(idpDomain).hasParameter("SAMLRequest");
|
||||
assertEquals(urlScheme, redirectUrl.getScheme());
|
||||
assertEquals(idpDomain, redirectUrl.getHost());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildAuthnRequestUrlWithQueryParam() throws Exception {
|
||||
String urlScheme = "http";
|
||||
|
||||
String spDomain = "sp.domain.example";
|
||||
String spUrl = urlScheme + "://" + spDomain;
|
||||
String spId = "cloudstack";
|
||||
|
||||
String idpDomain = "idp.domain.example";
|
||||
String idpQueryParam = "idpid=CX1298373";
|
||||
String idpUrl = urlScheme + "://" + idpDomain + "?" + idpQueryParam;
|
||||
String idpId = "identityProviderId";
|
||||
|
||||
String authnId = SAMLUtils.generateSecureRandomId();
|
||||
|
||||
SAMLProviderMetadata spMetadata = new SAMLProviderMetadata();
|
||||
spMetadata.setEntityId(spId);
|
||||
spMetadata.setSsoUrl(spUrl);
|
||||
|
||||
SAMLProviderMetadata idpMetadata = new SAMLProviderMetadata();
|
||||
idpMetadata.setSsoUrl(idpUrl);
|
||||
idpMetadata.setEntityId(idpId);
|
||||
|
||||
URI redirectUrl = new URI(SAMLUtils.buildAuthnRequestUrl(authnId, spMetadata, idpMetadata, SAML2AuthManager.SAMLSignatureAlgorithm.value()));
|
||||
assertThat(redirectUrl).hasScheme(urlScheme).hasHost(idpDomain).hasParameter("idpid").hasParameter("SAMLRequest");
|
||||
assertEquals(urlScheme, redirectUrl.getScheme());
|
||||
assertEquals(idpDomain, redirectUrl.getHost());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildLogoutRequest() throws Exception {
|
||||
String logoutUrl = "http://logoutUrl";
|
||||
|
||||
1
pom.xml
1
pom.xml
@ -118,6 +118,7 @@
|
||||
<cs.testng.version>7.1.0</cs.testng.version>
|
||||
<cs.wiremock.version>2.27.2</cs.wiremock.version>
|
||||
<cs.xercesImpl.version>2.12.2</cs.xercesImpl.version>
|
||||
<cs.assertj.version>3.23.1</cs.assertj.version>
|
||||
|
||||
<!-- Dependencies versions -->
|
||||
<cs.amqp-client.version>5.10.0</cs.amqp-client.version>
|
||||
|
||||
@ -44,7 +44,7 @@ keytool -genkey -storepass "$KS_PASS" -keypass "$KS_PASS" -alias "$ALIAS" -keyal
|
||||
|
||||
# Generate CSR
|
||||
rm -f "$CSR_FILE"
|
||||
addresses=$(ip address | grep inet | awk '{print $2}' | sed 's/\/.*//g' | grep -v '^169.254.' | grep -v '^127.0.0.1' | grep -v '^::1' | sed 's/^/ip:/g' | tr '\r\n' ',')
|
||||
addresses=$(ip address | grep inet | awk '{print $2}' | sed 's/\/.*//g' | grep -v '^169.254.' | grep -v '^127.0.0.1' | egrep -v '^::1|^fe80' | grep -v '^::1' | sed 's/^/ip:/g' | tr '\r\n' ',')
|
||||
keytool -certreq -storepass "$KS_PASS" -alias "$ALIAS" -file $CSR_FILE -keystore "$KS_FILE" -ext san="$addresses" > /dev/null 2>&1
|
||||
cat "$CSR_FILE"
|
||||
|
||||
|
||||
@ -194,4 +194,4 @@ class TestEventsResource(cloudstackTestCase):
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
super(TestEventsResource, cls).tearDownClass()
|
||||
super(TestEventsResource, cls).tearDownClass()
|
||||
|
||||
@ -54,8 +54,7 @@
|
||||
:ref="field.name"
|
||||
:name="field.name"
|
||||
:key="index"
|
||||
:label="field.name==='keyword' ?
|
||||
('listAnnotations' in $store.getters.apis ? $t('label.annotation') : $t('label.name')) : $t('label.' + field.name)">
|
||||
:label="retrieveFieldLabel(field.name)">
|
||||
<a-select
|
||||
allowClear
|
||||
v-if="field.type==='list'"
|
||||
@ -242,6 +241,19 @@ export default {
|
||||
if (!this.visibleFilter) return
|
||||
this.initFormFieldData()
|
||||
},
|
||||
retrieveFieldLabel (fieldName) {
|
||||
if (fieldName === 'groupid') {
|
||||
fieldName = 'group'
|
||||
}
|
||||
if (fieldName === 'keyword') {
|
||||
if ('listAnnotations' in this.$store.getters.apis) {
|
||||
return this.$t('label.annotation')
|
||||
} else {
|
||||
return this.$t('label.name')
|
||||
}
|
||||
}
|
||||
return this.$t('label.' + fieldName)
|
||||
},
|
||||
async initFormFieldData () {
|
||||
const arrayField = []
|
||||
this.fields = []
|
||||
@ -260,7 +272,10 @@ export default {
|
||||
if (item === 'clusterid' && !('listClusters' in this.$store.getters.apis)) {
|
||||
return true
|
||||
}
|
||||
if (['zoneid', 'domainid', 'state', 'level', 'clusterid', 'podid', 'entitytype', 'type'].includes(item)) {
|
||||
if (item === 'groupid' && !('listInstanceGroups' in this.$store.getters.apis)) {
|
||||
return true
|
||||
}
|
||||
if (['zoneid', 'domainid', 'state', 'level', 'clusterid', 'podid', 'groupid', 'entitytype', 'type'].includes(item)) {
|
||||
type = 'list'
|
||||
} else if (item === 'tags') {
|
||||
type = 'tag'
|
||||
@ -282,6 +297,7 @@ export default {
|
||||
let domainIndex = -1
|
||||
let podIndex = -1
|
||||
let clusterIndex = -1
|
||||
let groupIndex = -1
|
||||
|
||||
if (arrayField.includes('type')) {
|
||||
if (this.$route.path === '/guestnetwork' || this.$route.path.includes('/guestnetwork/')) {
|
||||
@ -330,6 +346,12 @@ export default {
|
||||
promises.push(await this.fetchClusters())
|
||||
}
|
||||
|
||||
if (arrayField.includes('groupid')) {
|
||||
groupIndex = this.fields.findIndex(item => item.name === 'groupid')
|
||||
this.fields[groupIndex].loading = true
|
||||
promises.push(await this.fetchInstanceGroups())
|
||||
}
|
||||
|
||||
if (arrayField.includes('entitytype')) {
|
||||
const entityTypeIndex = this.fields.findIndex(item => item.name === 'entitytype')
|
||||
this.fields[entityTypeIndex].loading = true
|
||||
@ -378,6 +400,12 @@ export default {
|
||||
this.fields[clusterIndex].opts = this.sortArray(cluster[0].data)
|
||||
}
|
||||
}
|
||||
if (groupIndex > -1) {
|
||||
const groups = response.filter(item => item.type === 'groupid')
|
||||
if (groups && groups.length > 0) {
|
||||
this.fields[groupIndex].opts = this.sortArray(groups[0].data)
|
||||
}
|
||||
}
|
||||
}).finally(() => {
|
||||
if (zoneIndex > -1) {
|
||||
this.fields[zoneIndex].loading = false
|
||||
@ -391,6 +419,9 @@ export default {
|
||||
if (clusterIndex > -1) {
|
||||
this.fields[clusterIndex].loading = false
|
||||
}
|
||||
if (groupIndex > -1) {
|
||||
this.fields[groupIndex].loading = false
|
||||
}
|
||||
this.fillFormFieldValues()
|
||||
})
|
||||
},
|
||||
@ -468,6 +499,19 @@ export default {
|
||||
})
|
||||
})
|
||||
},
|
||||
fetchInstanceGroups () {
|
||||
return new Promise((resolve, reject) => {
|
||||
api('listInstanceGroups', { listAll: true }).then(json => {
|
||||
const instancegroups = json.listinstancegroupsresponse.instancegroup
|
||||
resolve({
|
||||
type: 'groupid',
|
||||
data: instancegroups
|
||||
})
|
||||
}).catch(error => {
|
||||
reject(error.response.headers['x-description'])
|
||||
})
|
||||
})
|
||||
},
|
||||
fetchGuestNetworkTypes () {
|
||||
const types = []
|
||||
if (this.apiName.indexOf('listNetworks') > -1) {
|
||||
|
||||
@ -75,7 +75,7 @@ export default {
|
||||
}
|
||||
return fields
|
||||
},
|
||||
searchFilters: ['name', 'zoneid', 'domainid', 'account', 'tags'],
|
||||
searchFilters: ['name', 'zoneid', 'domainid', 'account', 'groupid', 'tags'],
|
||||
details: () => {
|
||||
var fields = ['displayname', 'name', 'id', 'state', 'ipaddress', 'ip6address', 'templatename', 'ostypename', 'serviceofferingname', 'isdynamicallyscalable', 'haenable', 'hypervisor', 'boottype', 'bootmode', 'account', 'domain', 'zonename']
|
||||
const listZoneHaveSGEnabled = store.getters.zones.filter(zone => zone.securitygroupsenabled === true)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user