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

Commit 1e71a44

Browse files
author
Jose Luis Barrueta
authored
Merge pull request #1154 from stormpath/Issue-1144-Ignore-UnknownProviderId
1144 Fix problem with unknown provider Ids
2 parents a8b215b + 5a36ee7 commit 1e71a44

9 files changed

Lines changed: 248 additions & 26 deletions

File tree

impl/src/main/java/com/stormpath/sdk/impl/ds/DefaultDataStore.java

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@
1717

1818
import com.stormpath.sdk.api.ApiKey;
1919
import com.stormpath.sdk.cache.CacheManager;
20-
import com.stormpath.sdk.impl.api.ApiKeyResolver;
21-
import com.stormpath.sdk.impl.authc.credentials.ClientCredentials;
2220
import com.stormpath.sdk.http.HttpMethod;
21+
import com.stormpath.sdk.impl.api.ApiKeyResolver;
2322
import com.stormpath.sdk.impl.authc.credentials.ApiKeyCredentials;
23+
import com.stormpath.sdk.impl.authc.credentials.ClientCredentials;
2424
import com.stormpath.sdk.impl.cache.DisabledCacheManager;
2525
import com.stormpath.sdk.impl.ds.api.ApiKeyQueryFilter;
2626
import com.stormpath.sdk.impl.ds.api.DecryptApiKeySecretFilter;
@@ -42,6 +42,7 @@
4242
import com.stormpath.sdk.impl.http.support.DefaultRequest;
4343
import com.stormpath.sdk.impl.http.support.UserAgent;
4444
import com.stormpath.sdk.impl.oauth.OAuthTokenRevoked;
45+
import com.stormpath.sdk.impl.provider.IdentityProviderType;
4546
import com.stormpath.sdk.impl.query.DefaultCriteria;
4647
import com.stormpath.sdk.impl.query.DefaultOptions;
4748
import com.stormpath.sdk.impl.resource.AbstractResource;
@@ -274,21 +275,23 @@ public <T extends Resource, R extends T> R getResource(String href, Class<T> par
274275
Assert.notEmpty(idClassMap, "idClassMap cannot be null or empty.");
275276

276277
ResourceDataResult result = getResourceData(href, parent, null);
277-
Map<String,?> data = result.getData();
278+
Map<String, ?> data = result.getData();
278279

279-
if (Collections.isEmpty(data)) {
280+
if (Collections.isEmpty(data) || !data.containsKey(childIdProperty)) {
280281
throw new IllegalStateException(childIdProperty + " could not be found in: " + data + ".");
281282
}
282283

283-
String childClassName = null;
284-
Object val = data.get(childIdProperty);
285-
if (val != null) {
286-
childClassName = String.valueOf(val);
284+
Object propertyValue = data.get(childIdProperty);
285+
if (propertyValue == null) {
286+
throw new IllegalStateException("No Class mapping could be found for " + childIdProperty + ".");
287287
}
288-
Class<? extends R> childClass = idClassMap.get(childClassName);
288+
289+
Class<? extends R> childClass = idClassMap.get(propertyValue.toString());
289290

290291
if (childClass == null) {
291-
throw new IllegalStateException("No Class mapping could be found for " + childIdProperty + ".");
292+
childClass = idClassMap.get(IdentityProviderType.DEFAULT.getNameKey());
293+
Assert.state(childClass != null, "No Class mapping could be found to instantiate resource.");
294+
log.warn("Could not find class for '{}' with value '{}'. Using '{}' as fallback.", childIdProperty, propertyValue, childClass);
292295
}
293296

294297
return instantiate(childClass, data, result.getUri().getQuery());

impl/src/main/java/com/stormpath/sdk/impl/provider/DefaultProvider.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
import java.util.Map;
2323

2424
/**
25-
* This DefaultProvider represents Stormpath as a Provider. For example, the provider of a Stormpath-owned directory is
26-
* "stormpath".
25+
* This DefaultProvider represents a {@link IdentityProviderType#DEFAULT} provider. For example, the provider of is
26+
* "a-new-social-provider".
2727
*
2828
* @since 1.0.beta
2929
*/
@@ -46,7 +46,7 @@ public Map<String, Property> getPropertyDescriptors() {
4646

4747
@Override
4848
protected String getConcreteProviderId() {
49-
return IdentityProviderType.STORMPATH.getNameKey();
49+
return getString(PROVIDER_ID);
5050
}
5151

5252
}

impl/src/main/java/com/stormpath/sdk/impl/provider/IdentityProviderType.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.stormpath.sdk.provider.*;
2020
import com.stormpath.sdk.provider.saml.SamlProvider;
2121
import com.stormpath.sdk.provider.saml.SamlProviderData;
22+
import com.stormpath.sdk.provider.saml.StormpathProvider;
2223

2324
import java.util.Collections;
2425
import java.util.HashMap;
@@ -31,7 +32,7 @@
3132
*/
3233
public enum IdentityProviderType {
3334

34-
STORMPATH("stormpath", Provider.class, ProviderData.class),
35+
STORMPATH("stormpath", StormpathProvider.class, ProviderData.class),
3536

3637
FACEBOOK("facebook", FacebookProvider.class, FacebookProviderData.class),
3738

@@ -50,7 +51,12 @@ public enum IdentityProviderType {
5051
/**
5152
* @since 1.0.RC8
5253
*/
53-
SAML("saml", SamlProvider.class, SamlProviderData.class);
54+
SAML("saml", SamlProvider.class, SamlProviderData.class),
55+
56+
/**
57+
* @since 1.2.0
58+
*/
59+
DEFAULT("default", Provider.class, ProviderData.class);
5460

5561
private static final Map<String, IdentityProviderType> IDENTITY_PROVIDER_MAP;
5662
public static final Map<String, Class<? extends Provider>> IDENTITY_PROVIDER_CLASS_MAP;
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright 2016 Stormpath, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.stormpath.sdk.impl.provider.saml;
17+
18+
import com.stormpath.sdk.impl.ds.InternalDataStore;
19+
import com.stormpath.sdk.impl.provider.AbstractProvider;
20+
import com.stormpath.sdk.impl.provider.IdentityProviderType;
21+
import com.stormpath.sdk.impl.resource.Property;
22+
import com.stormpath.sdk.provider.saml.StormpathProvider;
23+
24+
import java.util.Map;
25+
26+
/**
27+
* This DefaultProvider represents Stormpath as a Provider. For example, the provider of a Stormpath-owned directory is
28+
* "stormpath".
29+
*
30+
* @since 1.2.2
31+
*/
32+
public class DefaultStormpathProvider extends AbstractProvider implements StormpathProvider {
33+
34+
private static final Map<String, Property> PROPERTY_DESCRIPTORS = createPropertyDescriptorMap(PROVIDER_ID, CREATED_AT, MODIFIED_AT);
35+
36+
public DefaultStormpathProvider(InternalDataStore dataStore) {
37+
super(dataStore);
38+
}
39+
40+
public DefaultStormpathProvider(InternalDataStore dataStore, Map<String, Object> properties) {
41+
super(dataStore, properties);
42+
}
43+
44+
@Override
45+
public Map<String, Property> getPropertyDescriptors() {
46+
return PROPERTY_DESCRIPTORS;
47+
}
48+
49+
@Override
50+
protected String getConcreteProviderId() {
51+
return IdentityProviderType.STORMPATH.getNameKey();
52+
}
53+
}

impl/src/test/groovy/com/stormpath/sdk/impl/directory/DefaultDirectoryTest.groovy

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import com.stormpath.sdk.impl.ds.InternalDataStore
3535
import com.stormpath.sdk.impl.group.DefaultGroupList
3636
import com.stormpath.sdk.impl.organization.DefaultOrganizationAccountStoreMappingList
3737
import com.stormpath.sdk.impl.organization.DefaultOrganizationList
38-
import com.stormpath.sdk.impl.provider.DefaultProvider
38+
import com.stormpath.sdk.impl.provider.saml.DefaultStormpathProvider
3939
import com.stormpath.sdk.impl.provider.IdentityProviderType
4040
import com.stormpath.sdk.impl.resource.CollectionReference
4141
import com.stormpath.sdk.impl.resource.ResourceReference
@@ -165,7 +165,7 @@ class DefaultDirectoryTest {
165165
andReturn(new DefaultTenant(internalDataStore, properties.tenant))
166166

167167
expect(internalDataStore.getResource(properties.provider.href, Provider.class, "providerId", IdentityProviderType.IDENTITY_PROVIDER_CLASS_MAP))
168-
.andReturn(new DefaultProvider(internalDataStore, properties.provider))
168+
.andReturn(new DefaultStormpathProvider(internalDataStore, properties.provider))
169169

170170
expect(internalDataStore.instantiate(PasswordPolicy, properties.passwordPolicy)).
171171
andReturn(new DefaultPasswordPolicy(internalDataStore, properties.passwordPolicy))
@@ -258,9 +258,9 @@ class DefaultDirectoryTest {
258258
assertTrue(resource instanceof DefaultTenant && resource.getHref().equals(properties.tenant.href))
259259

260260
resource = defaultDirectory.getProvider()
261-
assertTrue(resource instanceof DefaultProvider && resource.getHref().equals(properties.provider.href))
261+
assertTrue(resource instanceof DefaultStormpathProvider && resource.getHref().equals(properties.provider.href))
262262
resource = defaultDirectory.getProvider() //Second invocation must not internally call internalDataStore.getResource(...) as it is already fully available in the internal properties
263-
assertTrue(resource instanceof DefaultProvider && resource.getHref().equals(properties.provider.href))
263+
assertTrue(resource instanceof DefaultStormpathProvider && resource.getHref().equals(properties.provider.href))
264264

265265
resource = defaultDirectory.getPasswordPolicy()
266266
assertTrue(resource instanceof DefaultPasswordPolicy && resource.getHref().equals(properties.passwordPolicy.href))

impl/src/test/groovy/com/stormpath/sdk/impl/ds/DefaultDataStoreTest.groovy

Lines changed: 87 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,21 @@ import com.stormpath.sdk.api.ApiKey
1919
import com.stormpath.sdk.cache.Caches
2020
import com.stormpath.sdk.impl.api.ApiKeyResolver
2121
import com.stormpath.sdk.impl.api.DefaultApiKeyResolver
22-
import com.stormpath.sdk.impl.authc.credentials.ApiKeyCredentials
2322
import com.stormpath.sdk.impl.application.DefaultApplication
23+
import com.stormpath.sdk.impl.authc.credentials.ApiKeyCredentials
2424
import com.stormpath.sdk.impl.http.RequestExecutor
2525
import com.stormpath.sdk.impl.http.Response
2626
import com.stormpath.sdk.impl.http.support.DefaultRequest
2727
import com.stormpath.sdk.impl.provider.DefaultGoogleProviderData
2828
import com.stormpath.sdk.impl.provider.IdentityProviderType
2929
import com.stormpath.sdk.impl.query.DefaultOptions
3030
import com.stormpath.sdk.impl.util.BaseUrlResolver
31-
import com.stormpath.sdk.provider.*
31+
import com.stormpath.sdk.provider.FacebookProvider
32+
import com.stormpath.sdk.provider.GithubProvider
33+
import com.stormpath.sdk.provider.GoogleProviderData
34+
import com.stormpath.sdk.provider.Provider
35+
import com.stormpath.sdk.provider.ProviderData
36+
import com.stormpath.sdk.provider.Providers
3237
import com.stormpath.sdk.query.Options
3338
import com.stormpath.sdk.resource.Resource
3439
import org.testng.annotations.Test
@@ -213,6 +218,45 @@ class DefaultDataStoreTest {
213218
verify(requestExecutor, response, facebookProvider)
214219
}
215220

221+
222+
@Test
223+
void getSpecificResourceUnknownProviderId() {
224+
def requestExecutor = createStrictMock(RequestExecutor)
225+
def response = createStrictMock(Response)
226+
def facebookProvider = createStrictMock(FacebookProvider)
227+
def apiKeyCredentials = createStrictMock(ApiKeyCredentials)
228+
def apiKeyResolver = createStrictMock(ApiKeyResolver)
229+
230+
def responseMap = [href: "https://api.stormpath.com/v1/directories/5fgF3o89Ph5nbJzY6EVSct/provider",
231+
createdAt: "2014-04-01T22:05:25.661Z",
232+
modifiedAt: "2014-04-01T22:05:53.177Z",
233+
clientId: "237396459765014",
234+
clientSecret: "a93fae44d2a4f21d4de6201aae9b849a",
235+
providerId: "unknown"
236+
]
237+
def mapMarshaller = new JacksonMapMarshaller();
238+
// convert String into InputStream
239+
InputStream is = new ByteArrayInputStream(mapMarshaller.marshal(responseMap).getBytes());
240+
241+
def childIdProperty = "providerId"
242+
def map = IdentityProviderType.IDENTITY_PROVIDER_CLASS_MAP
243+
244+
expect(requestExecutor.executeRequest(anyObject(DefaultRequest))).andReturn(response)
245+
expect(response.isError()).andReturn(false)
246+
expect(response.hasBody()).andReturn(true)
247+
expect(response.getBody()).andReturn(is)
248+
249+
replay(requestExecutor, response, facebookProvider)
250+
251+
def defaultDataStore = new DefaultDataStore(requestExecutor, "https://api.stormpath.com/v1", apiKeyCredentials, apiKeyResolver)
252+
253+
def provider = defaultDataStore.getResource("https://api.stormpath.com/v1/directories/5fgF3o89Ph5nbJzY6EVSct/provider", Provider, childIdProperty, map)
254+
255+
assertEquals "unknown", provider.getProviderId()
256+
257+
verify(requestExecutor, response, facebookProvider)
258+
}
259+
216260
@Test
217261
void getSpecificResourceNonexistentPropertyException() {
218262
def requestExecutor = createStrictMock(RequestExecutor)
@@ -247,7 +291,47 @@ class DefaultDataStoreTest {
247291
defaultDataStore.getResource("https://api.stormpath.com/v1/directories/5fgF3o89Ph5nbJzY6EVSct/provider", Provider, childIdProperty, map)
248292
fail("should have thrown")
249293
} catch (IllegalStateException e) {
250-
assertEquals(e.getMessage(), "No Class mapping could be found for nonexistentProperty.")
294+
assertTrue e.getMessage().contains("nonexistentProperty could not be found in:"), "Message '${e.getMessage()}' doesn't contain expected: 'nonexistentProperty could not be found in:' "
295+
}
296+
297+
verify(requestExecutor, response, facebookProvider)
298+
}
299+
300+
@Test
301+
void getSpecificResourceNullProviderIdExceptionIsThrown() {
302+
def requestExecutor = createStrictMock(RequestExecutor)
303+
def response = createStrictMock(Response)
304+
def facebookProvider = createStrictMock(FacebookProvider)
305+
def apiKeyCredentials = createStrictMock(ApiKeyCredentials)
306+
def apiKeyResolver = createStrictMock(ApiKeyResolver)
307+
308+
def responseMap = [href: "https://api.stormpath.com/v1/directories/5fgF3o89Ph5nbJzY6EVSct/provider",
309+
createdAt: "2014-04-01T22:05:25.661Z",
310+
modifiedAt: "2014-04-01T22:05:53.177Z",
311+
clientId: "237396459765014",
312+
clientSecret: "a93fae44d2a4f21d4de6201aae9b849a",
313+
providerId: null
314+
]
315+
def mapMarshaller = new JacksonMapMarshaller();
316+
// convert String into InputStream
317+
InputStream is = new ByteArrayInputStream(mapMarshaller.marshal(responseMap).getBytes())
318+
319+
def childIdProperty = "providerId"
320+
def map = IdentityProviderType.IDENTITY_PROVIDER_CLASS_MAP
321+
322+
expect(requestExecutor.executeRequest(anyObject(DefaultRequest))).andReturn(response)
323+
expect(response.isError()).andReturn(false)
324+
expect(response.hasBody()).andReturn(true)
325+
expect(response.getBody()).andReturn(is)
326+
327+
replay(requestExecutor, response, facebookProvider)
328+
329+
def defaultDataStore = new DefaultDataStore(requestExecutor, "https://api.stormpath.com/v1", apiKeyCredentials, apiKeyResolver)
330+
try {
331+
defaultDataStore.getResource("https://api.stormpath.com/v1/directories/5fgF3o89Ph5nbJzY6EVSct/provider", Provider, childIdProperty, map)
332+
fail("should have thrown")
333+
} catch (IllegalStateException e) {
334+
assertEquals e.getMessage(), "No Class mapping could be found for providerId."
251335
}
252336

253337
verify(requestExecutor, response, facebookProvider)

impl/src/test/groovy/com/stormpath/sdk/impl/provider/DefaultProviderTest.groovy

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,15 @@ class DefaultProviderTest {
5050

5151
def properties = [href: "https://api.stormpath.com/v1/directories/iouertnw48ufsjnsDFSf/provider",
5252
createdAt: "2013-10-01T23:38:55.000Z",
53-
modifiedAt: "2013-10-02T23:38:55.000Z"
53+
modifiedAt: "2013-10-02T23:38:55.000Z",
54+
providerId: "my-social-thing"
5455
]
5556

5657
def internalDataStore = createStrictMock(InternalDataStore)
5758
def provider = new DefaultProvider(internalDataStore, properties)
5859

5960
assertEquals(provider.getHref(), "https://api.stormpath.com/v1/directories/iouertnw48ufsjnsDFSf/provider")
60-
assertEquals(provider.getProviderId(), "stormpath")
61+
assertEquals(provider.getProviderId(), "my-social-thing")
6162
assertEquals(provider.getCreatedAt().format("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", TimeZone.getTimeZone("GMT")), "2013-10-01T23:38:55.000Z")
6263
assertEquals(provider.getModifiedAt().format("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", TimeZone.getTimeZone("GMT")) , "2013-10-02T23:38:55.000Z")
6364
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright 2016 Stormpath, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.stormpath.sdk.impl.provider
18+
19+
import com.stormpath.sdk.impl.ds.InternalDataStore
20+
import com.stormpath.sdk.impl.provider.saml.DefaultStormpathProvider
21+
import com.stormpath.sdk.impl.resource.DateProperty
22+
import com.stormpath.sdk.impl.resource.StringProperty
23+
import com.stormpath.sdk.provider.Provider
24+
import org.testng.annotations.Test
25+
26+
import static org.easymock.EasyMock.createStrictMock
27+
import static org.testng.Assert.assertEquals
28+
import static org.testng.Assert.assertTrue
29+
30+
/**
31+
* @since 1.2.2
32+
*/
33+
class DefaultStormpathProviderTest {
34+
35+
@Test
36+
void testGetPropertyDescriptors() {
37+
38+
def provider = new DefaultStormpathProvider(createStrictMock(InternalDataStore))
39+
40+
def propertyDescriptors = provider.getPropertyDescriptors()
41+
42+
assertEquals(propertyDescriptors.size(), 3)
43+
44+
assertTrue(propertyDescriptors.get("providerId") instanceof StringProperty)
45+
assertTrue(propertyDescriptors.get("createdAt") instanceof DateProperty)
46+
assertTrue(propertyDescriptors.get("modifiedAt") instanceof DateProperty)
47+
assertTrue(Provider.isInstance(provider))
48+
}
49+
50+
@Test
51+
void testMethods() {
52+
53+
def properties = [href: "https://api.stormpath.com/v1/directories/iouertnw48ufsjnsDFSf/provider",
54+
createdAt: "2013-10-01T23:38:55.000Z",
55+
modifiedAt: "2013-10-02T23:38:55.000Z",
56+
]
57+
58+
def internalDataStore = createStrictMock(InternalDataStore)
59+
def provider = new DefaultStormpathProvider(internalDataStore, properties)
60+
61+
assertEquals(provider.getHref(), "https://api.stormpath.com/v1/directories/iouertnw48ufsjnsDFSf/provider")
62+
assertEquals(provider.getProviderId(), "stormpath")
63+
assertEquals(provider.getCreatedAt().format("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", TimeZone.getTimeZone("GMT")), "2013-10-01T23:38:55.000Z")
64+
assertEquals(provider.getModifiedAt().format("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", TimeZone.getTimeZone("GMT")) , "2013-10-02T23:38:55.000Z")
65+
}
66+
67+
}

0 commit comments

Comments
 (0)