diff --git a/api/src/main/java/com/stormpath/sdk/okta/Link.java b/api/src/main/java/com/stormpath/sdk/okta/Link.java new file mode 100644 index 0000000000..69a0439fa8 --- /dev/null +++ b/api/src/main/java/com/stormpath/sdk/okta/Link.java @@ -0,0 +1,31 @@ +package com.stormpath.sdk.okta; + + +import java.net.URL; + +/** + * HAL based link representation. + */ +public class Link { + + private URL href; + private String method; + + public URL getHref() { + return href; + } + + public Link setHref(URL href) { + this.href = href; + return this; + } + + public String getMethod() { + return method; + } + + public Link setMethod(String method) { + this.method = method; + return this; + } +} diff --git a/api/src/main/java/com/stormpath/sdk/okta/Profile.java b/api/src/main/java/com/stormpath/sdk/okta/Profile.java new file mode 100644 index 0000000000..53d3921e63 --- /dev/null +++ b/api/src/main/java/com/stormpath/sdk/okta/Profile.java @@ -0,0 +1,115 @@ +package com.stormpath.sdk.okta; + +import com.stormpath.sdk.resource.Deletable; +import com.stormpath.sdk.resource.Saveable; + +import java.util.Map; + +/** + * Okta User Profile wrapper + */ +public interface Profile extends Map { + + + String getLogin(); + void setLogin(String login); + + String getFirstName(); + void setFirstName(String firstName); + + + String getLastName(); + void setLastName(String lastName); + + String getMiddleName(); + void setMiddleName(String middleName); + + String getEmail(); + void setEmail(String email); + + String getDisplayName(); + void setDisplayName(String displayName); + +/* + + // Other Okta profile attributes not yet added above. + + Base + Honorific prefix honorificPrefix + string + Base + Honorific suffix honorificSuffix + string + Base + Title title + string + + Base + Nickname nickName + string + Base + Profile Url profileUrl + string + Base + Secondary email secondEmail + string + Base + Mobile phone mobilePhone + string + Base + Primary phone primaryPhone + string + Base + Street address streetAddress + string + Base + City city + string + Base + State state + string + Base + Zip code zipCode + string + Base + Country code countryCode + string + Base + Postal Address postalAddress + string + Base + Preferred language preferredLanguage + string + Base + Locale locale + string + Base + Time zone timezone + string + Base + User type userType + string + Base + Employee number employeeNumber + string + Base + Cost center costCenter + string + Base + Organization organization + string + Base + Division division + string + Base + Department department + string + Base + ManagerId managerId + string + Base + Manager manager + string + Base + */ +} diff --git a/api/src/main/java/com/stormpath/sdk/okta/User.java b/api/src/main/java/com/stormpath/sdk/okta/User.java new file mode 100644 index 0000000000..099e8b03b7 --- /dev/null +++ b/api/src/main/java/com/stormpath/sdk/okta/User.java @@ -0,0 +1,42 @@ +package com.stormpath.sdk.okta; + +import java.util.Date; +import java.util.Map; + +/** + * User object mapped into the Okta API. + */ +public interface User { + + String getId(); + User setId(String string); + + // "activated": null, ???? + + UserStatus getStatus(); + User setStatus(UserStatus userStatus); + + Date getStatusChanged(); + User setStatusChanged(Date statusChangedDate); + + Date getCreated(); + User setCreated(Date createdDate); + + Date getLastLogin(); + User setLastLogin(Date lastLoginDate); + + Date getLastUpdated(); + User setLastUpdated(Date lastUpdatedDate); + + Date getPasswordChanged(); + User setPasswordChanged(Date passwordChangedDate); + + Profile getProfile(); + User setProfile(Profile profile); + + Map getLinks(); + User setLinks(Map links); + + Map getCredentials(); + User setCredentials(Map credentials); +} diff --git a/api/src/main/java/com/stormpath/sdk/okta/UserStatus.java b/api/src/main/java/com/stormpath/sdk/okta/UserStatus.java new file mode 100644 index 0000000000..49a04f4c69 --- /dev/null +++ b/api/src/main/java/com/stormpath/sdk/okta/UserStatus.java @@ -0,0 +1,23 @@ +package com.stormpath.sdk.okta; + +/** + * An {@code UserStatus} represents the various states a user may be in. + */ +public enum UserStatus { + + STAGED, + + PROVISIONED, + + ACTIVE, + + RECOVERY, + + PASSWORD_EXPIRED, + + LOCKED_OUT, + + SUSPENDED, + + DEPROVISIONED +} \ No newline at end of file diff --git a/impl/pom.xml b/impl/pom.xml index 3f9a40834d..852dd011a0 100644 --- a/impl/pom.xml +++ b/impl/pom.xml @@ -72,6 +72,11 @@ snakeyaml true + + + org.hamcrest + java-hamcrest + diff --git a/impl/src/main/java/com/stormpath/sdk/impl/okta/DefaultProfile.java b/impl/src/main/java/com/stormpath/sdk/impl/okta/DefaultProfile.java new file mode 100644 index 0000000000..03d66e39cc --- /dev/null +++ b/impl/src/main/java/com/stormpath/sdk/impl/okta/DefaultProfile.java @@ -0,0 +1,149 @@ +package com.stormpath.sdk.impl.okta; + +import com.stormpath.sdk.impl.application.ConfigurableProperty; +import com.stormpath.sdk.impl.resource.AbstractPropertyRetriever; +import com.stormpath.sdk.lang.Objects; +import com.stormpath.sdk.okta.Profile; +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +/** + * + */ +public class DefaultProfile extends ConfigurableProperty implements Profile { + + private static final String LOGIN = "login"; + private static final String FIRST_NAME = "firstName"; + private static final String LAST_NAME = "lastName"; + private static final String MIDDLE_NAME = "middleName"; + private static final String EMAIL = "email"; + private static final String DISPLAY_NAME = "displayName"; + + public DefaultProfile(String name, Map properties, AbstractPropertyRetriever parent) { + super(name, properties, parent); + } + + @Override + public String getLogin() { + return Objects.nullSafeToString(get(LOGIN)); + } + + @Override + public void setLogin(String login) { + put(LOGIN, login); + } + + @Override + public String getFirstName() { + return Objects.nullSafeToString(get(FIRST_NAME)); + } + + @Override + public void setFirstName(String firstName) { + put(FIRST_NAME, firstName); + } + + @Override + public String getLastName() { + return Objects.nullSafeToString(get(LAST_NAME)); + } + + @Override + public void setLastName(String lastName) { + put(LAST_NAME, lastName); + } + + @Override + public String getMiddleName() { + return Objects.nullSafeToString(get(MIDDLE_NAME)); + } + + @Override + public void setMiddleName(String middleName) { + put(MIDDLE_NAME, middleName); + } + + @Override + public String getEmail() { + return Objects.nullSafeToString(get(EMAIL)); + } + + @Override + public void setEmail(String email) { + put(EMAIL, email); + } + + @Override + public String getDisplayName() { + return Objects.nullSafeToString(get(DISPLAY_NAME)); + } + + @Override + public void setDisplayName(String displayName) { + put(DISPLAY_NAME, displayName); + } + + + + @Override + public int size() { + return properties.size(); + } + + @Override + public boolean isEmpty() { + return properties.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return properties.containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + return properties.containsValue(value); + } + + @Override + public Object get(Object key) { + return properties.get(key); + } + + @Override + public Object put(String key, Object value) { + return properties.put(key, value); + } + + @Override + public Object remove(Object key) { + return properties.remove(key); + } + + @Override + public void putAll(Map m) { + properties.putAll(m); + } + + @Override + public void clear() { + properties.clear(); + } + + @Override + public Set keySet() { + return properties.keySet(); + } + + @Override + public Collection values() { + return properties.values(); + } + + @Override + public Set> entrySet() { + return properties.entrySet(); + } + +} diff --git a/impl/src/main/java/com/stormpath/sdk/impl/okta/DefaultUser.java b/impl/src/main/java/com/stormpath/sdk/impl/okta/DefaultUser.java new file mode 100644 index 0000000000..c1c01adb41 --- /dev/null +++ b/impl/src/main/java/com/stormpath/sdk/impl/okta/DefaultUser.java @@ -0,0 +1,165 @@ +package com.stormpath.sdk.impl.okta; + +import com.stormpath.sdk.impl.ds.InternalDataStore; +import com.stormpath.sdk.impl.resource.AbstractInstanceResource; +import com.stormpath.sdk.impl.resource.AbstractPropertyRetriever; +import com.stormpath.sdk.impl.resource.DateProperty; +import com.stormpath.sdk.impl.resource.EnumProperty; +import com.stormpath.sdk.impl.resource.MapProperty; +import com.stormpath.sdk.impl.resource.ParentAwareObjectProperty; +import com.stormpath.sdk.impl.resource.Property; +import com.stormpath.sdk.impl.resource.StringProperty; +import com.stormpath.sdk.okta.Link; +import com.stormpath.sdk.okta.Profile; +import com.stormpath.sdk.okta.User; +import com.stormpath.sdk.okta.UserStatus; + +import java.util.Date; +import java.util.Map; + +/** + * Default implementation of {@link com.stormpath.sdk.okta.User}. + */ +public class DefaultUser extends AbstractInstanceResource implements User { + + // SIMPLE PROPERTIES + private static final StringProperty ID = new StringProperty("id"); + private static final EnumProperty STATUS = new EnumProperty<>("status", UserStatus.class); + private static final DateProperty STATUS_CHANGED = new DateProperty("statusChanged"); + private static final DateProperty CREATED = new DateProperty("created"); + private static final DateProperty LAST_LOGIN = new DateProperty("lastLogin"); + private static final DateProperty LAST_UPDATED = new DateProperty("lastUpdated"); + private static final DateProperty PASSWORD_CHANGED = new DateProperty("passwordChanged"); + + private static final ParentAwareObjectProperty PROFILE = new ParentAwareObjectProperty<>("profile", DefaultProfile.class, AbstractPropertyRetriever.class); + private static final MapProperty LINKS = new MapProperty("_links"); + private static final MapProperty CREDENTIALS = new MapProperty("credentials"); + + + private static final Map PROPERTY_DESCRIPTORS = createPropertyDescriptorMap(); + + public DefaultUser(InternalDataStore dataStore) { + super(dataStore); + } + + public DefaultUser(InternalDataStore dataStore, Map properties) { + super(dataStore, properties); + } + + @Override + public Map getPropertyDescriptors() { + return PROPERTY_DESCRIPTORS; + } + + @Override + public String getId() { + return getString(ID); + } + + @Override + public User setId(String id) { + setProperty(ID, id); + return this; + } + + @Override + public UserStatus getStatus() { + return getEnumProperty(STATUS); + } + + @Override + public User setStatus(UserStatus userStatus) { + setProperty(STATUS, userStatus); + return this; + } + + @Override + public Date getStatusChanged() { + return getDateProperty(STATUS_CHANGED); + } + + @Override + public User setStatusChanged(Date statusChangedDate) { + setProperty(STATUS_CHANGED, statusChangedDate); + return this; + } + + @Override + public Date getCreated() { + return getDateProperty(CREATED); + } + + @Override + public User setCreated(Date createdDate) { + setProperty(CREATED, createdDate); + return this; + } + + @Override + public Date getLastLogin() { + return getDateProperty(LAST_LOGIN); + } + + @Override + public User setLastLogin(Date lastLoginDate) { + setProperty(LAST_LOGIN, lastLoginDate); + return this; + } + + @Override + public Date getLastUpdated() { + return getDateProperty(LAST_UPDATED); + } + + @Override + public User setLastUpdated(Date lastUpdatedDate) { + setProperty(LAST_UPDATED, lastUpdatedDate); + return this; + } + + @Override + public Date getPasswordChanged() { + return getDateProperty(PASSWORD_CHANGED); + } + + @Override + public User setPasswordChanged(Date passwordChangedDate) { + setProperty(PASSWORD_CHANGED, passwordChangedDate); + return this; + } + + @Override + public Profile getProfile() { + return getParentAwareObjectProperty(PROFILE); + } + + @Override + public User setProfile(Profile profile) { + setProperty(PROFILE, profile); + return this; + } + + @Override + public Map getLinks() { + return getMap(LINKS); + } + + @Override + public User setLinks(Map links) { + setProperty(LINKS, links); + return this; + } + + @Override + public Map getCredentials() { + return getMap(CREDENTIALS); + } + + @Override + public User setCredentials(Map credentials) { + setProperty(CREDENTIALS, credentials); + return this; + } + + +} diff --git a/impl/src/main/java/com/stormpath/sdk/impl/okta/resource/ProfileProperty.java b/impl/src/main/java/com/stormpath/sdk/impl/okta/resource/ProfileProperty.java new file mode 100644 index 0000000000..c012291bd4 --- /dev/null +++ b/impl/src/main/java/com/stormpath/sdk/impl/okta/resource/ProfileProperty.java @@ -0,0 +1,15 @@ +package com.stormpath.sdk.impl.okta.resource; + +import com.stormpath.sdk.impl.resource.Property; +import com.stormpath.sdk.okta.Profile; + + +/** + * This is a {@link com.stormpath.sdk.okta.Profile} backed subclass of a {@link Property}. + */ +public class ProfileProperty extends Property { + + public ProfileProperty(String name) { + super(name, Profile.class); + } +} diff --git a/impl/src/test/groovy/com/stormpath/sdk/impl/okta/DefaultUserTest.groovy b/impl/src/test/groovy/com/stormpath/sdk/impl/okta/DefaultUserTest.groovy new file mode 100644 index 0000000000..9b00330383 --- /dev/null +++ b/impl/src/test/groovy/com/stormpath/sdk/impl/okta/DefaultUserTest.groovy @@ -0,0 +1,79 @@ +package com.stormpath.sdk.impl.okta + +import com.stormpath.sdk.cache.CacheManager +import com.stormpath.sdk.client.AuthenticationScheme +import com.stormpath.sdk.impl.api.ApiKeyResolver +import com.stormpath.sdk.impl.authc.credentials.ApiKeyCredentials +import com.stormpath.sdk.impl.client.DefaultClient +import com.stormpath.sdk.impl.ds.InternalDataStore +import com.stormpath.sdk.impl.http.authc.RequestAuthenticatorFactory +import com.stormpath.sdk.impl.oauth.DefaultOAuthPolicy +import com.stormpath.sdk.impl.util.BaseUrlResolver +import com.stormpath.sdk.lang.Classes +import com.stormpath.sdk.okta.User +import org.testng.annotations.Test + +import static org.easymock.EasyMock.createStrictMock +import static org.easymock.EasyMock.expect +import static org.powermock.api.easymock.PowerMock.createStrictMock +import static org.powermock.api.easymock.PowerMock.mockStatic +import static org.powermock.api.easymock.PowerMock.replayAll +import static org.testng.Assert.assertEquals +import static org.testng.Assert.fail +import static org.hamcrest.Matchers.* +import static org.hamcrest.MatcherAssert.* + + +/** + * Tests for {@link DefaultUser}. + */ +class DefaultUserTest { + + @Test + void validateClientInstantiateTest() { + + def apiKeyCredentials = createStrictMock(ApiKeyCredentials) + def apiKeyResolver = createStrictMock(ApiKeyResolver) + def cacheManager = createStrictMock(CacheManager) + def requestAuthenticatorFactory = createStrictMock(RequestAuthenticatorFactory) + def baseUrlResolver = createStrictMock(BaseUrlResolver) + + replayAll() + + def client = new DefaultClient(apiKeyCredentials, + apiKeyResolver, + baseUrlResolver, + null, + cacheManager, + AuthenticationScheme.BASIC, + requestAuthenticatorFactory, + 3600) + + def user = client.instantiate(User) + assertThat(user, instanceOf(DefaultUser)) + } + + @Test + void basicTest() { + def internalDataStore = createStrictMock(InternalDataStore) + + def properties = [ + href: "https://api.stormpath.com/v1/mock/35YM3OwioW9PVtfLOh6q1e/oauth/token", + id: "test-id", + profile: [ + firstName: "joe", + customField: "foobar" + ] + ] + + DefaultUser defaultUser = new DefaultUser(internalDataStore, properties) + assertThat defaultUser.id, is("test-id") + assertThat defaultUser.profile.getFirstName(), is("joe") + assertThat defaultUser.profile, allOf( + hasEntry("firstName", "joe"), + hasEntry("customField", "foobar") + ) + + + } +} diff --git a/pom.xml b/pom.xml index afd7305185..1d0d6a37ee 100644 --- a/pom.xml +++ b/pom.xml @@ -550,6 +550,12 @@ + + + org.hamcrest + java-hamcrest + 2.0.0.0 +