Skip to content
This repository was archived by the owner on Dec 14, 2018. It is now read-only.

Commit 16141d0

Browse files
author
Brian Retterer
committed
Add SAML support
1 parent af66c4b commit 16141d0

22 files changed

+858
-180
lines changed

.travis.yml

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,23 @@
11
language: php
2-
32
php:
43
- 5.6
54
- 5.5
65
- 5.4
7-
86
sudo: false
9-
107
services:
11-
- redis-server
12-
- memcached
13-
8+
- redis-server
9+
- memcached
1410
before_script:
1511
- composer self-update
1612
- travis_retry composer install --prefer-dist --no-interaction
1713
- mkdir -p ~/.phpenv/versions/$(phpenv version-name)/etc
1814
- echo "extension = memcached.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
1915
- echo "extension = redis.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
20-
2116
script:
22-
- travis_retry vendor/bin/phpunit --coverage-clover build/logs/clover.xml
23-
17+
- travis_retry vendor/bin/phpunit --coverage-clover build/logs/clover.xml
2418
after_success:
25-
- bash <(curl -s https://codecov.io/bash)
26-
19+
- bash <(curl -s https://codecov.io/bash)
20+
notifications:
21+
hipchat:
22+
rooms:
23+
secure: DN61iUJL9kBtBfPqdHZk67IvadLdSR8+X2dV79qxx/OAFjhu+rW/K0PQp2VEgpUwHwROJxPhxiwXO8OLaA8v7rD7yp9diYwG8gjrmbOcLOphPhMuRlxSfDddWS7Eo7C177KfB2/WEbFhXhav4rDeso8xRUvGJwxqe1TYLQ7cwZo=

src/DataStore/DefaultDataStore.php

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ public function save(Resource $resource, $returnType = null)
151151

152152
if (!strlen($href))
153153
{
154-
throw new InvalidArgumentException('save may only be called on objects that have already been persisted (i.e. they have an existing href).');
154+
throw new \InvalidArgumentException('save may only be called on objects that have already been persisted (i.e. they have an existing href).');
155155
}
156156

157157
if ($this->needsToBeFullyQualified($href))
@@ -298,7 +298,6 @@ private function applyDefaultRequestHeaders(Request $request)
298298
->setPhpVersion(phpversion())
299299
->build();
300300

301-
302301
if ($body = $request->getBody())
303302
{
304303
$headers['Content-Type'] = 'application/json';
@@ -351,12 +350,30 @@ private function toStdClass(Resource $resource, $customData = false)
351350
$property = $this->toStdClass($property);
352351
}
353352

353+
$properties->$name = $property;
354+
}
354355

356+
return $properties;
357+
}
355358

356-
$properties->$name = $property;
359+
private function objectArrayToStdClass($property)
360+
{
361+
$properties = new \stdClass();
362+
363+
$class = new \ReflectionClass($property);
364+
365+
$classProperties = $class->getProperties();
366+
367+
foreach($classProperties as $prop) {
368+
$method = 'get'.ucfirst($prop->name);
369+
if(method_exists($property, $method)) {
370+
371+
$properties->{$prop->name} = $property->$method();
372+
}
357373
}
358374

359375
return $properties;
376+
360377
}
361378

362379
private function toSimpleReference($propertyName, \stdClass $properties)

src/DataStore/DefaultResourceFactory.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
* See the License for the specific language governing permissions and
1818
* limitations under the License.
1919
*/
20+
use Stormpath\Saml\AttributeStatementMappingRuleBuilder;
21+
use Stormpath\Saml\AttributeStatementMappingRulesBuilder;
22+
2023
class DefaultResourceFactory implements ResourceFactory
2124
{
2225

@@ -43,11 +46,19 @@ public function instantiate($className, array $constructorArgs)
4346
$newClass->customData;
4447
}
4548

49+
if($newClass instanceof \Stormpath\Resource\SamlProvider) {
50+
$newClass = $this->convertSamlAttributeStatementMappingRules($newClass);
51+
}
52+
4653
return $newClass;
4754
}
4855

4956
private function qualifyClassName($className)
5057
{
58+
if (class_exists($className) && strstr($className, 'Stormpath')) {
59+
return $className;
60+
}
61+
5162
if (strpos($className, self::RESOURCE_PATH) === false)
5263
{
5364
return self::RESOURCE_PATH .$className;
@@ -57,4 +68,26 @@ private function qualifyClassName($className)
5768

5869
}
5970

71+
private function convertSamlAttributeStatementMappingRules($newClass)
72+
{
73+
$mappingRules = $newClass->getAttributeStatementMappingRules();
74+
if(null === $mappingRules) {
75+
return $newClass;
76+
}
77+
78+
$items = $mappingRules->getItems();
79+
$newItems = [];
80+
81+
$itemBuilder = new AttributeStatementMappingRuleBuilder();
82+
foreach($items as $item) {
83+
$newItems[] = $itemBuilder->setName($item->name)
84+
->setNameFormat($item->nameFormat)
85+
->setAccountAttributes($item->accountAttributes)
86+
->build();
87+
}
88+
89+
$newClass->getAttributeStatementMappingRules()->items = $newItems;
90+
return $newClass;
91+
}
92+
6093
}

src/Http/HttpClientRequestExecutor.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public function __construct(RequestSigner $signer = null)
4242
public function executeRequest(Request $request, $redirectsLimit = 10)
4343
{
4444
$requestHeaders = $request->getHeaders();
45+
4546
$apiKey = $request->getApiKey();
4647

4748
if ($apiKey)

src/Resource/Application.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class Application extends InstanceResource implements Deletable
4646
const LOGIN_ATTEMPTS = "loginAttempts";
4747
const OAUTH_POLICY = "oAuthPolicy";
4848
const CUSTOM_DATA = "customData";
49+
const AUTHORIZED_CALLBACK_URIS = "authorizedCallbackUris";
4950

5051
const PATH = "applications";
5152

@@ -112,6 +113,32 @@ public function setStatus($status)
112113
}
113114
}
114115

116+
/**
117+
* Array that defines the authorized URIs that the IdP can return your
118+
* user to. These should be URIs that you host yourself.
119+
*
120+
* @since 1.13.0
121+
* @param array $uris
122+
* @return self
123+
*/
124+
public function setAuthorizedCallbackUris(array $uris = [])
125+
{
126+
$this->setProperty(self::AUTHORIZED_CALLBACK_URIS, $uris);
127+
return $this;
128+
}
129+
130+
/**
131+
* Returns Array that defines the authorized URIs that the IdP can return
132+
* your user to. These should be URIs that you host yourself.
133+
*
134+
* @since 1.13.0
135+
* @return array
136+
*/
137+
public function getAuthorizedCallbackUris()
138+
{
139+
return (array) $this->getProperty(self::AUTHORIZED_CALLBACK_URIS);
140+
}
141+
115142
public function getTenant(array $options = array())
116143
{
117144
return $this->getResourceProperty(self::TENANT, Stormpath::TENANT, $options);

src/Resource/SamlProvider.php

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,26 @@
1919

2020
use Stormpath\Client;
2121
use Stormpath\DataStore\InternalDataStore;
22+
use Stormpath\Saml\AttributeStatementMappingRules;
2223
use Stormpath\Stormpath;
2324

2425
/** @since 1.13.0 */
25-
class SamlProvider extends Provider
26+
class SamlProvider extends Provider implements Saveable
2627
{
27-
const SSO_LOGIN_URL = "ssoLoginUrl";
28-
const SSO_LOGOUT_URL = "ssoLogoutUrl";
29-
const ENCODED_X509_SIGNING_CERT = "encodedX509SigningCert";
30-
const REQUEST_SIGNATURE_ALGOITHM = "requestSignatureAlgorithm";
31-
const SAML_PROVIDER_METADATA = "serviceProviderMetadata";
32-
const SAML_PROVIDER_ID = "saml";
28+
const SSO_LOGIN_URL = "ssoLoginUrl";
29+
const SSO_LOGOUT_URL = "ssoLogoutUrl";
30+
const ENCODED_X509_SIGNING_CERT = "encodedX509SigningCert";
31+
const REQUEST_SIGNATURE_ALGOITHM = "requestSignatureAlgorithm";
32+
const ATTRIBUTE_STATEMENT_MAPPING_RULES = "attributeStatementMappingRules";
33+
const SAML_PROVIDER_METADATA = "serviceProviderMetadata";
34+
35+
const SAML_PROVIDER_ID = "saml";
36+
37+
public function __construct(InternalDataStore $dataStore = null, \stdClass $properties = null)
38+
{
39+
parent::__construct($dataStore, $properties);
40+
$this->setProperty(self::PROVIDER_ID, self::SAML_PROVIDER_ID);
41+
}
3342

3443
/**
3544
* Retreive a SAML Provider based on the Href.
@@ -46,27 +55,21 @@ public static function get($href, array $options = [])
4655
$href = $href.'/'.self::PATH;
4756
}
4857

49-
return Client::get($href, Stormpath::SAML_PROVIDER, Directory::PATH, $options);
58+
return Client::get($href, Stormpath::SAML_PROVIDER, null, $options);
5059
}
5160

5261
/**
53-
* Create an instance of SAML Provider.
62+
* Create a new SAML Provider instance with properties.
5463
*
5564
* @since 1.13.0
56-
* @param null|array $properties
65+
* @param array|null $properties
5766
* @return \Stormpath\Resource\SamlProvider
5867
*/
5968
public static function instantiate($properties = null)
6069
{
6170
return Client::instantiate(Stormpath::SAML_PROVIDER, $properties);
6271
}
6372

64-
public function __construct(InternalDataStore $dataStore = null, \stdClass $properties = null)
65-
{
66-
parent::__construct($dataStore, $properties);
67-
$this->setProperty(self::PROVIDER_ID, self::SAML_PROVIDER_ID);
68-
}
69-
7073
/**
7174
* The URL at the IdP to which SAML authentication requests should be sent.
7275
* This is often called an “SSO URL”, “Login URL” or “Sign-in URL”
@@ -121,13 +124,26 @@ public function getRequestSignatureAlgorithm()
121124
*
122125
* @since 1.13.0
123126
* @param array $options
124-
* @return null|\Stormpath\DataStore\a
127+
* @return \Stormpath\Resource\SamlProviderData
125128
*/
126129
public function getServiceProviderMetadata(array $options = [])
127130
{
128-
return $this->getResourceProperty(self::SAML_PROVIDER_METADATA, Stormpath::SAML_PROVIDER_METADATA, $options);
131+
return $this->getResourceProperty(self::SAML_PROVIDER_METADATA, Stormpath::SAML_PROVIDER_DATA, $options);
129132
}
130133

134+
/**
135+
* Get the Attribute Statement Mapping Rules for the SAML Provider.
136+
*
137+
* @since 1.13.0
138+
* @param array $options
139+
* @return \Stormpath\Saml\AttributeStatementMappingRules
140+
*/
141+
public function getAttributeStatementMappingRules(array $options = [])
142+
{
143+
return $this->getResourceProperty(self::ATTRIBUTE_STATEMENT_MAPPING_RULES, Stormpath::ATTRIBUTE_STATEMENT_MAPPING_RULES, $options);
144+
}
145+
146+
131147
/**
132148
* Set the URL at the IdP to which SAML authentication requests should be sent.
133149
* This is often called an “SSO URL”, “Login URL” or “Sign-in URL”
@@ -185,4 +201,21 @@ public function setRequestSignatureAlgorithm($requestSignatureAlgorithm)
185201
return $this;
186202
}
187203

204+
/**
205+
* Set the Attribute Statement Mapping Rules for the SAML Provider.
206+
*
207+
* @since 1.13.0
208+
* @param AttributeStatementMappingRules $attributeStatementMappingRules
209+
* @return self
210+
*/
211+
public function setAttributeStatementMappingRules(AttributeStatementMappingRules $attributeStatementMappingRules)
212+
{
213+
$this->setProperty(self::ATTRIBUTE_STATEMENT_MAPPING_RULES, $attributeStatementMappingRules);
214+
return $this;
215+
}
216+
217+
public function save()
218+
{
219+
$this->getDataStore()->save($this);
220+
}
188221
}

src/Resource/SamlProviderData.php

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,66 @@
11
<?php
2+
/*
3+
* Copyright 2016 Stormpath, Inc.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
217

3-
namespace Resource;
18+
namespace Stormpath\Resource;
419

5-
class SamlProviderData
20+
use Stormpath\Stormpath;
21+
22+
/** @since 1.13.0 */
23+
class SamlProviderData extends InstanceResource
624
{
25+
const ENTITY_ID = 'entityId';
26+
const X509_SIGNING_CERT = 'x509SigningCert';
27+
const ASSERTION_CONSUMER_SERVICE_POST_ENDPOINT = 'assertionConsumerServicePostEndpoint';
28+
29+
/**
30+
* This returns the value of the Entity Id from the IdP XML
31+
*
32+
* @since 1.13.0
33+
* @return string
34+
*/
35+
public function getEntityId()
36+
{
37+
return $this->getProperty(self::ENTITY_ID);
38+
}
39+
40+
/**
41+
* The certificate that is used to sign the requests sent to the IdP. If
42+
* you retrieve XML, the certificate will be embedded. If you retrieve
43+
* JSON, you’ll have to follow a further /x509certificates link to
44+
* retrieve it.
45+
*
46+
* @since 1.13.0
47+
* @param array $options
48+
* @return null|\Stormpath\Resource\X509SigningCert
49+
*/
50+
public function getX509SigningCert(array $options = [])
51+
{
52+
return $this->getResourceProperty(self::X509_SIGNING_CERT, Stormpath::X509_SIGNING_CERT, $options);
53+
}
754

55+
/**
56+
* This is the location the IdP will send its response to.
57+
*
58+
* @since 1.13.0
59+
* @param array $options
60+
* @return null|\Stormpath\Resource\AssertionConsumerServicePostEndpoint
61+
*/
62+
public function getAssertionConsumerServicePostEndpoint(array $options = [])
63+
{
64+
return $this->getResourceProperty(self::ASSERTION_CONSUMER_SERVICE_POST_ENDPOINT, Stormpath::ASSERTION_CONSUMER_SERVICE_POST_ENDPOINT);
65+
}
866
}

0 commit comments

Comments
 (0)